I have the next example in express js and mongoose. Exist a relationship between student and province:
app.get('/example', async (req, res) => {
const provinces = await Province.find();
let studentsByProvince = [];
for (let prov of provinces) {
const st = await Student.count({ province: prov });
studentsByProvince.push({ province: prov.province, totalStudents: st });
}
res.json(studentsByProvince);});
This is not efficient since inside the cycle the search is carried out sequentially. I solve it this way:
app.get('/example2', async (req, res) => {
const provinces = await Province.find();
let studentsByProvince = [];
let studentsByProvincePromises = [];
for (let prov of provinces) {
const studentPromise = Student.count({ province: prov });
studentsByProvincePromises.push(studentPromise);
}
const studentsByProvinceResult = await Promise.all(studentsByProvincePromises);
for (let [index, prov] of provinces.entries()) {
studentsByProvince.push({ province: prov.province, totalStudents: studentsByProvinceResult[index] });
}
res.json(studentsByProvince);});
I already resolved the issue of executing it in parallel, however I have to go through the cycle twice, since the query returns a promise and not the result. There is async await some way to solve this example similar to the first way, but in parallel.
You can attach a callback to the promises in the first loop:
app.get('/example2', async (req, res) => {
const provinces = await Province.find();
let studentsByProvincePromises = [];
for (let prov of provinces) {
const studentPromise = Student.count({ province: prov })
.then(st => ({ province: prov.province, totalStudents: st });
studentsByProvincePromises.push(studentPromise);
}
const studentsByProvince = await Promise.all(studentsByProvincePromises);
res.json(studentsByProvince);
});
Using Array.prototype.map
will make stuff look more concise:
app.get('/example2', async (req, res) => {
const provinces = await Province.find();
const studentsByProvince = await Promise.all(
provinces.map(prov => {
return (Student.count({ province: prov })
.then(totalStudents => ({ province: prov.province, totalStudents })
)
})
);
res.json(studentsByProvince);
});
I think you can achieve this differently and even save a database query. Since you want all provinces anyways (you can also programmatically add a filter to the pipeline) why not do an aggregation?
Student.aggregate([
{
$group:{
_id: "$province", // this is the property we are grouping by
count: { $sum: 1 }
}
}
])
This will return an array of objects with the following structure:
[
{
"_id" : "provinceName",
"count" : 6
},
....
]
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.