简体   繁体   中英

Querying subdocuments array with filter and return original documents with mongoose

I am using mongoose and have the following structure the documents:

{
  user: {
    comments: [
      { title: "mpla", active: true },
      { title: "mpla", active: false }
    ]
  }
}
...

How can i return all my documents, but only the active comments in the comments array.

You will have to use mongodb aggregation, so the query will be:

db.collectionName.aggregate(
 {
   $unwind:  $user.comments
 }
) 

This will decontruct the comments array and will include other fields like the id included in each document. So eg lets say your document was:

{ "_id": 1, "user" : 
   { "comments": 
     [ { "title": "mpla", "active" : true }, { "title": "mpla", "active" : false }  }]
    }
}

Once we run the above given query it will result in the following documents:

{ "_id": 1, "user" : 
   { "comments": { "title": "mpla", "active" : true }  
   }
 }
}

{ "_id": 1, "user" : 
   { "comments": { "title": "mpla", "active" : false }   
   }
 }
}

As you can see now we have two separate documents you can now query them using $match operator and group them back into an array using $group operator. Hope that answers your question.

Taking a general case here where main documents may have others fields other than user and user doc itself may have other fields as well:

Sample docs:

[
  {
    user: {
      comments: [
        { title: "mpla", active: true },
        { title: "mpla", active: false }
      ],
      name: "abc",
      gender: "male",
      createdDate: new Date("2019-04-01"),
      modifiedDate: new Date("2019-08-24")
    },
    story: {
      name: "a mocking bird",
      year: 1994,
      cost: "$5"
    }
  },
  {
    user: {
      comments: [
        { title: "nope", active: true },
        { title: "hello", active: true }
      ],
      name: "pqr",
      gender: "female",
      createdDate: new Date("2019-05-01"),
      modifiedDate: new Date("2019-09-24")
    },
    story: {
      name: "a kite runner",
      year: 2005,
      cost: "$2"
    }
  }
]

Now here all fields with documents must be returned but comments array should contain active=true docs only.

Aggregation query with $filter and $project :

db.collection.aggregate([
  {
    $project: {
      _id: 1,
      story: 1,
      user: {
        name: 1,
        gender: 1,
        createdDate: 1,
        modifiedDate: 1,
        comments: {
          $filter: {
            input: "$user.comments",
            as: "comment",
            cond: { $eq: ["$$comment.active", true] }
          }
        }
      }
    }
  }
]).pretty();

Output documents:

{
    "_id" : ObjectId("5d8bb8c66926e92a334275d4"),
    "user" : {
        "name" : "abc",
        "gender" : "male",
        "createdDate" : ISODate("2019-04-01T00:00:00Z"),
        "modifiedDate" : ISODate("2019-08-24T00:00:00Z"),
        "comments" : [
            {
                "title" : "mpla",
                "active" : true
            }
        ]
    },
    "story" : {
        "name" : "a mocking bird",
        "year" : 1994,
        "cost" : "$5"
    }
},
{
    "_id" : ObjectId("5d8bb8c66926e92a334275d5"),
    "user" : {
        "name" : "pqr",
        "gender" : "female",
        "createdDate" : ISODate("2019-05-01T00:00:00Z"),
        "modifiedDate" : ISODate("2019-09-24T00:00:00Z"),
        "comments" : [
            {
                "title" : "nope",
                "active" : true
            },
            {
                "title" : "hello",
                "active" : true
            }
        ]
    },
    "story" : {
        "name" : "a kite runner",
        "year" : 2005,
        "cost" : "$2"
    }
}

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM