从 MongoDB 检索图像的最佳方法是什么?
我有一个使用 GridFS 从 MongoDB 存储和检索图像的 Web 应用程序。我的问题是,当用户发出请求提示服务器从数据库检索图像时,需要很长时间。
例如,仅检索数据库中的两个文档,然后循环访问每个文档以获取与每个文档关联的图像的请求最多可能需要 45 秒。在本例中,从数据库检索的图像总数约为 10 张。
这是我的方法:
// 1. Query the database
var users = await User.find({ 'key’': value });
// 5. Use GridFs to get the image and return the result
const createStream = (filename) => {
return new Promise((resolve, reject) => {
let readstream = gfs.createReadStream(filename);
let fileChunks = [];
readstream.on('data', function (chunk) {
fileChunks.push(chunk);
});
readstream.on('end', function () {
let concatFile = Buffer.concat(fileChunks);
let imageFormated = Buffer(concatFile).toString("base64");
resolve(imageFormated)
});
})
}
// 4. Iterate though each of the images info and retrieve the file name so it can be used with gfs.createReadStream( );
const iterateImages = async (currentPlaceImages) => {
let imagesFormattedArray = [];
for (var i = 0; i < currentPlaceImages.length; i++) {
let filename = currentPlaceImages[i].filename;
// console.log(filename);
let imageFormated = await createStream(filename);
// console.log(imageFormated);
imagesFormattedArray.push(imageFormated)
if (i === currentPlaceImages.length - 1) {
return imagesFormattedArray
}
}
}
// 3. favPlaces represents a field-value pair of each document that contains an object of ‘favorite places’, each of which with a ‘placeImage’ array of all the images associated with a place
const getImagesOfPlace = async (favPlaces) => {
let imagesStreamArray = [];
for (var w = 0; w < favPlaces.length; w++) {.
let currentPlaceImages = favPlaces[w]['placeImage'];
let imagesStream = await iterateImages(currentPlaceImages);
imagesStreamArray.push(imagesStream);
if (w === favPlaces.length - 1) {
return imagesStreamArray;
}
};
}
// 2. Loop through the documents retrieved from the database and access the field - value pair that contains the information of the images that I want to retrieve using GridFs
let arrayOfUsers = [];
const getImages = async () => {
let arrayOfFormattedImages = [];
for (var i = 0; i < users.length; i++) {
let favPlaces = users[i]['favoritePlaces'];
let stream = await getImagesOfPlace(favPlaces);
userObj['imageFormatted'] = stream;
arrayOfUsers.push(userObj);
}
};
await getImages();
如前所述,这种方法需要很长时间才能获得服务器回复。如果有人知道更好、更有效、更快速的方法,请告诉我。
谢谢!
I have a web application that stores and retrieves images from MongoDB using GridFS. My issue is that when the user makes a request that prompts the server to retrieve images from the database, it takes a very long time.
For instance, a request that retrieves only two documents in the database and then loops through each document to get the images associated with each document can take up to 45 seconds. In this case, the total amount of images retrieved from the database is around 10.
Here is my approach:
// 1. Query the database
var users = await User.find({ 'key’': value });
// 5. Use GridFs to get the image and return the result
const createStream = (filename) => {
return new Promise((resolve, reject) => {
let readstream = gfs.createReadStream(filename);
let fileChunks = [];
readstream.on('data', function (chunk) {
fileChunks.push(chunk);
});
readstream.on('end', function () {
let concatFile = Buffer.concat(fileChunks);
let imageFormated = Buffer(concatFile).toString("base64");
resolve(imageFormated)
});
})
}
// 4. Iterate though each of the images info and retrieve the file name so it can be used with gfs.createReadStream( );
const iterateImages = async (currentPlaceImages) => {
let imagesFormattedArray = [];
for (var i = 0; i < currentPlaceImages.length; i++) {
let filename = currentPlaceImages[i].filename;
// console.log(filename);
let imageFormated = await createStream(filename);
// console.log(imageFormated);
imagesFormattedArray.push(imageFormated)
if (i === currentPlaceImages.length - 1) {
return imagesFormattedArray
}
}
}
// 3. favPlaces represents a field-value pair of each document that contains an object of ‘favorite places’, each of which with a ‘placeImage’ array of all the images associated with a place
const getImagesOfPlace = async (favPlaces) => {
let imagesStreamArray = [];
for (var w = 0; w < favPlaces.length; w++) {.
let currentPlaceImages = favPlaces[w]['placeImage'];
let imagesStream = await iterateImages(currentPlaceImages);
imagesStreamArray.push(imagesStream);
if (w === favPlaces.length - 1) {
return imagesStreamArray;
}
};
}
// 2. Loop through the documents retrieved from the database and access the field - value pair that contains the information of the images that I want to retrieve using GridFs
let arrayOfUsers = [];
const getImages = async () => {
let arrayOfFormattedImages = [];
for (var i = 0; i < users.length; i++) {
let favPlaces = users[i]['favoritePlaces'];
let stream = await getImagesOfPlace(favPlaces);
userObj['imageFormatted'] = stream;
arrayOfUsers.push(userObj);
}
};
await getImages();
Here is a visual representation of the flow
As mentioned, this approach takes very long to get a server response. If any one knows a better, more effective and fast way of doing this, please let me know.
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
因为您使用
for
循环,所以图像将一个接一个地加载,而不是一次全部加载,循环将迭代然后等待,然后再次迭代并等待等等......您需要触发所有异步立即执行操作并等待所有操作完成,使用Array.map
的 Promise.all 是一种方法。尝试这样的事情:Because you use
for
loops the images will load one after the other instead of all at once, the loop will iterate then await then iterate again and await and so on.... You need to fire all async actions at once and await for all of them to finish,Promise.all
usingArray.map
is a way to do it. Try something like this: