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