Reputation: 568
I have an array of images which I want to upload to MongoDB all at once:
images = [{
id: 123,
alt: "my image",
buffer: <Buffer>,
mimetype: "image/jpeg"
}]
I understand you should use Promise.all()
for this, but I'm clueless about promises and was only able to string together the following where Image
is my Mongoose Schema:
const uploaded_images = images.map(img => {
return {
id: img.id,
promise: Image.create({
image: { data: img.buffer, contentType: img.mimetype },
alt: img.alt,
})
};
});
await Promise.all(uploaded_images.map(img => img.promise));
However, when I now try to access the _id
property of the newly uploaded images, I am getting undefined
uploaded_images.forEach(img => {
console.log(img.promise); // gives Promise { { image: { data: new Binary(...), contentType: 'image/jpeg' }, alt: 'my image', _id: new ObjectId(...) } }
console.log(img.promise._id); // gives Undefined
})
How can I access the _id
property?
After some more testing: Before the await Promise.all()
line when I console log the array, I get [{ id: '013150333796129177', promise: Promise { <pending> } }]
. Then after that line when I console log it, I get [{ id: '013150333796129177', promise: Promise { [Object] } }]
. Does that mean it is resolved? Why cant I access the Object?
Upvotes: 1
Views: 69
Reputation: 164811
Waiting for all the .promise
properties to resolve won't change them from promises to data; .promise
will always be a Promise.
I think you want something more like this...
const uploaded_images = await Promise.all(
images.map(async ({ alt, buffer, id, mimetype }) => ({
id,
image: await Image.create({
alt,
image: { data: buffer, contentType: mimetype },
}),
}))
);
uploaded_images.forEach((img) => {
console.log(img.id); // original id
console.log(img.image._id); // Image entity id
});
The async function used in the map()
callback will return a promise that resolves when the Image.create()
completes. Using Promise.all()
on this array of promises will complete once they've all resolved.
The above still inserts documents individually. If you want to batch-insert, you'd need to pass an array to Image.insertMany()
const imageDocs = await Image.insertMany(
images.map(({ alt, buffer, mimetype }) => ({
alt,
image: { data: buffer, contentType: mimeType },
})),
{
ordered: true,
}
);
const uploaded_images = imageDocs.map((image, i) => ({
id: images[i].id,
image,
}));
Note that combining the created docs with the id
properties from the original array is a little more hacky now.
Upvotes: 1