I have collection named "listing" with fields such as metadata and status. metadata is a object containing user object inside and status is a string.
The structure looks like this,
{ "status": "Active", "metadata": { "user": { "urlProfile": "", "averageRating": 5, "reviewCount": 2, "userId": "1244324" } } }
Now the status field have values such as "Active" and "Inactive". I need to group by those status and filter by the userId. so i have a function inside the helper as follows,
query: function (model, conditon, options) {
console.log(conditon, options);
return new Promise(function (resolve, reject) {
options = options || {};
model.find(conditon, {}, options).exec(function (error, data) {
if (error) {
reject(error);
}
resolve(data);
})
})
}
Question is how can i pass the group by along with the user id and query the data needed. Right now my querying part looks like this,
return dbService.query(sellerModel, {
'metadata.user.userId': userIdRetrieved
}, {});
how can i pass the group by condition? i looked for sample, did not find any solution till now.
Sample Collection

Expected Output:
[{
"Status": "Active",
"Results": {
"user": {
"urlProfile": "",
"averageRating": 5,
"reviewCount": 2,
"userId": "1244324"
}
}
}
,
{
"Status": "InActive",
"Results": {
"user": {
"urlProfile": "",
"averageRating": 5,
"reviewCount": 2,
"userId": "1244324"
}
}
}]
The find() function is used to find particular data from the MongoDB database. It takes 3 arguments and they are query (also known as a condition), query projection (used for mentioning which fields to include or exclude from the query), and the last argument is the general query options (like limit, skip, etc).
First, I discovered grouping with Mongoose is called Aggregate.
What is find() in Mongoose? Mongoose's find() method is a query to retrieve a document or documents that match a particular filter.
and it will return array? find returns an array always.
To get the desired output, you would need to use the aggregate method since it offers the operators which allow you to aggregate the documents and return the said result.
Consider constructing a pipeline that consists of a $group stage, whereby you aggregate the average rating via the $avg accumulator, the reviewCount with $sum and the other fields in the group using $first or $last. Your group by key is a subdocument with two fields Status and userId.
A final $project step would allow you to reshape the output from the above group aggregates to the desired form and the aggregate() method returns a query which you can then call exec() to get a Promise.
To explain the above framework, follow this example:
query: function (model, conditon, options) {
console.log(conditon, options);
options = options || {};
return model.aggregate([
{ "$match": conditon },
{
"$group": {
"_id": {
"Status": "$status",
"userId": "$metadata.user.userId"
},
"urlProfile": { "$first": "$metadata.user.urlProfile" },
"averageRating": { "$avg": "$metadata.user.averageRating" },
"reviewCount": { "$sum": "$metadata.user.reviewCount" }
}
},
{
"$project": {
"_id": 0,
"Status": "$_id.Status",
"Results": {
"user": {
"averageRating": "$averageRating",
"reviewCount": "$reviewCount",
"userId": "$_id.userId"
}
}
}
}
]).exec();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With