Mongoose: how to use aggregate and find together

81,241

Solution 1

For MongoDB 3.6 and greater, use the $expr operator which allows the use of aggregation expressions within the query language:

var followers_count = 30;
db.locations.find({
   "$expr": { 
       "$and": [
           { "$eq": ["$name", "development"] },
           { "$gte": [{ "$size": "$followers" }, followers_count ]}
       ]
    }
});

For non-compatible versions, you can use both the $match and $redact pipelines to query your collection. For example, if you want to query the locations collection where the name is 'development' and followers_count is greater than 30, run the following aggregate operation:

const followers_count = 30;
Locations.aggregate([
    { "$match": { "name": "development" } },
    {
        "$redact": {
            "$cond": [
                { "$gte": [ { "$size": "$followers" }, followers_count ] },
                "$$KEEP",
                "$$PRUNE"
            ]
        }
    }
]).exec((err, locations) => {
    if (err) throw err;
    console.log(locations);
})

or within a single pipeline as

Locations.aggregate([
    {
        "$redact": {
            "$cond": [
                { 
                    "$and": [
                        { "$eq": ["$name", "development"] },
                        { "$gte": [ { "$size": "$followers" }, followers_count ] }
                     ]
                },
                "$$KEEP",
                "$$PRUNE"
            ]
        }
    }
]).exec((err, locations) => {
    if (err) throw err;
    console.log(locations);
})

The above will return the locations with just the _id references from the users. To return the users documents as means to "populate" the followers array, you can then append the $lookup pipeline.


If the underlying Mongo server version is 3.4 and newer, you can run the pipeline as

let followers_count = 30;
Locations.aggregate([
    { "$match": { "name": "development" } },
    {
        "$redact": {
            "$cond": [
                { "$gte": [ { "$size": "$followers" }, followers_count ] },
                "$$KEEP",
                "$$PRUNE"
            ]
        }
    },
    {
        "$lookup": {
            "from": "users",
            "localField": "followers",
            "foreignField": "_id",
            "as": "followers"
        }
    }
]).exec((err, locations) => {
    if (err) throw err;
    console.log(locations);
})

else you would need to $unwind the followers array before applying $lookup and then regroup with $group pipeline after that:

let followers_count = 30;
Locations.aggregate([
    { "$match": { "name": "development" } },
    {
        "$redact": {
            "$cond": [
                { "$gte": [ { "$size": "$followers" }, followers_count ] },
                "$$KEEP",
                "$$PRUNE"
            ]
        }
    },
    { "$unwind": "$followers" },
    {
        "$lookup": {
            "from": "users",
            "localField": "followers",
            "foreignField": "_id",
            "as": "follower"
        }
    },
    { "$unwind": "$follower" },
    {
        "$group": {
            "_id": "$_id",
            "created": { "$first": "$created" },
            "name": { "$first": "$name" },
            "followers": { "$push": "$follower" }
        }
    }
]).exec((err, locations) => {
    if (err) throw err;
    console.log(locations);
})

Solution 2

You can use as the following:

db.locations.aggregate([
  {$match:{"your find query"}},
  {$project:{"your desired fields"}}
])

In the match you can do stuff like:

{{$match:{name:"whatever"}}

In the project, you can select the fields you want using numbers 0 or 1 like:

{$project:{_id:1,created:0,name:1}}

Which 0 means, do not put and 1 means put.

Share:
81,241

Related videos on Youtube

Colin Wang
Author by

Colin Wang

Senior Developer

Updated on July 09, 2022

Comments

  • Colin Wang
    Colin Wang almost 2 years

    How can I use aggregate and find together in Mongoose?
    i.e I have the following schema:

    const schema = new Mongoose.Schema({
      created: { type: Date, default: Date.now() },
      name: { type: String, default: 'development' }
      followers: [{ type: Mongoose.Schema.ObjectId, ref: 'Users'}]
    ...
    })
    
    export default Mongoose.model('Locations', schema)
    

    How can I query the users with only the fields name and followers_count.
    followers_count: the length of followers .

    There, I know we can use select to get only the field name.
    How can we get the count of followers?