Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Group by with find in mongoose?

Tags:

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 enter image description here

Expected Output:

[{
  "Status": "Active",
  "Results": {
    "user": {
      "urlProfile": "",
      "averageRating": 5,
      "reviewCount": 2,
      "userId": "1244324"
    }
  }
}
,
{
  "Status": "InActive",
  "Results": {
    "user": {
      "urlProfile": "",
      "averageRating": 5,
      "reviewCount": 2,
      "userId": "1244324"
    }
  }
}]
like image 238
Sajeetharan Avatar asked Apr 17 '17 18:04

Sajeetharan


People also ask

What does find do in Mongoose?

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).

WHAT IS group in Mongoose?

First, I discovered grouping with Mongoose is called Aggregate.

What does find function return in Mongoose?

What is find() in Mongoose? Mongoose's find() method is a query to retrieve a document or documents that match a particular filter.

Does find return an array Mongoose?

and it will return array? find returns an array always.


1 Answers

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();      
}
like image 151
chridam Avatar answered Sep 24 '22 10:09

chridam