Home > OS >  Mongoose Find all Documents by subdocument and filter out subdocs that dont match
Mongoose Find all Documents by subdocument and filter out subdocs that dont match

Time:02-18

I am trying to query all documents in a collection that contain specific user data WITHOUT returning all subdocuments (there are a ton of subdocuments)

Example Documents

[
    {
        "id": 1,
        "title": "Document 1",
        "users": [
            { "id": "a", "name": "User 1" },
            { "id": "b", "name": "User 1" },
        ]
    },
    {
        "id": 2,
        "title": "Document 2",
        "users": [
            { "id": "b", "name": "User 1" },
        ]
    },
    {
        "id": 3,
        "title": "Document 3",
        "users": [
            { "id": "a", "name": "User 1" },
            { "id": "b", "name": "User 1" },
            { "id": "c", "name": "User 1" },
        ]
    }
]

Here we have 3 documents in which use with id A is in 2 of them, to Query all documents where user A exists I am doing:

collection.findManyByQuery({
    users: {
        $elemMatch: {
            id: 'a'
        }
    }
})

This returns me documents with id 1 and 3 which is correct. HOWEVER I am trying to return the documents with ONLY user A object inside the users array so my result would look like this

[
    {
        "id": 1,
        "title": "Document 1",
        "users": [
            { "id": "a", "name": "User 1" },
        ]
    },
    {
        "id": 3,
        "title": "Document 3",
        "users": [
            { "id": "a", "name": "User 1" },
        ]
    }
]

I have tried $unwind: 'users' and a couple of filters but have not got the desired result.

CodePudding user response:

Use projection stage.

According to docs:

The projection parameter determines which fields are returned in the matching documents

So using users.$: 1 you are telling mongo: "Return the value from users that matches the criteria". In this case the criteria is id: "a".

db.collection.find({
  users: {
    $elemMatch: {
      id: "a"
    }
  }
},
{
  "users.$": 1
})

Example here

Also you can use users.id into find query like in this example

Maybe is a query more clean, only two lines:

db.collection.find({
  "users.id": "a"
},
{
  "users.$": 1
})

Edit:

To add more values to output (like title or id) you have to add to projection stage. By default projection only return the _id and the values with 1 or true.

Check this example

  • Related