I have to merge three arrays into one array of objects, where every i object contain value i from each array.
I have three arrays which contain data from firebase (arrays of url for thumbnails, url for full size images, and objects with metadata.
let finalArrayOfImagesAndMetadata = [];
// Getting array of download url's for every file
const getDownloadUrlFullFile = await Promise.all(getAllFilesList.items.map(itemRef => getDownloadURL(itemRef)));
const getDownloadUrlThumbnails = await Promise.all(getAllThumbnails.items.map(itemRef => getDownloadURL(itemRef)));
// Getting metadata for all files
const getMetadataForAllFiles = await Promise.all(getAllFilesList.items.map(itemRef => getMetadata(itemRef)));
I have managed to develop two ways of solvin this problem:
first:
// Merging full size image url, thumbnail url and metadata in one object
const processArray = async () => {
getDownloadUrlFullFile.forEach((o)=>{
finalArrayOfImagesAndMetadata.push({'fullImageUrl': o});
});
getDownloadUrlThumbnails.forEach((x, i)=>{
finalArrayOfImagesAndMetadata[i].imageUrl =x;
})
getMetadataForAllFiles.forEach((x, i)=>{
const element = x.customMetadata;
finalArrayOfImagesAndMetadata[i] = {...finalArrayOfImagesAndMetadata[i], ...element};
})
console.log(finalArrayOfImagesAndMetadata)
return finalArrayOfImagesAndMetadata;
}
second:
// Merging full size image url, thumbnail url and metadata in one object
const processArray = async () => {
return new Promise(async function (resolve, reject) {
for (let i =0 ; i<getDownloadUrlFullFile.length; i ){
const getSpecificFileThumbnail = getDownloadUrlThumbnails[i];
const getFileMetadata = loadedMetaData[i].customMetadata;
const imageUrl = {'imageUrl': getSpecificFileThumbnail};
const fullImageUrl = {'fullImageUrl': getDownloadUrlFullFile[i]}
finalArrayOfImagesAndMetadata.push({...getFileMetadata, ...imageUrl, fullImageUrl});
if ( finalArrayOfImagesAndMetadata.length === getDownloadUrlThumbnails.length) {
return (finalArrayOfImagesAndMetadata);
}
resolve (finalArrayOfImagesAndMetadata);
}})}
Both solution works but, is there some more sophisticated and better way of solving this? Maybe something with waiting until every step of writing to array is done?
Other words: how to do it like a pro?
CodePudding user response:
Yes, a few ways depending on the desired shape of the resulting data...
const urls = await Promise.all(getAllFilesList.items.map(itemRef => getDownloadURL(itemRef)));
const thumbnails = await Promise.all(getAllThumbnails.items.map(itemRef => getDownloadURL(itemRef)));
const metadata = await Promise.all(getAllFilesList.items.map(itemRef => getMetadata(itemRef)));
// simplest merge is just a concatenation
const oneBigArray = [...urls, ...thumbnails, ...metadata]
// another sort of merge is to have the arrays as props in an object
const oneBigObject = { urls, thumbnails, metadata }; // notice no spread ... operator
A true "merge" would key off of something common in each of the objects in the arrays to build an array of objects like:
[
{ key: 'some common key',
url: 'some url',
thumbnail: 'some url',
metadata: { /* some meta data object */ }
},
// ...
];
Elaborating here requires knowing more about the returned objects, for example, if there's a key in each of the returned objects that ties them to their friends in the other arrays.
CodePudding user response:
You can iterate over the elements like your first option, but use the map method to construct the new array. Then you can use the index argument to get the other data (like your second option) so:
const mergedArray = getDownloadUrlFullFile.map((fullImageUrl, i)=>({
// Shorthand to set fullImageUrl: fullImageUrl
fullImageUrl,
// assign the property directly
'imageUrl': getSpecificFileThumbnail[i],
// You can also spread values if you want them directly on the object
{...loadedMetaData[i].customMetadata}
}));
If you want to combine the requests and the data merging together you can use the Promise.all and Promise.map pattern https://www.techiediaries.com/promise-all-map-async-await-example/
