Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MongoDB query with elemMatch for nested array data

Tags:

mongodb

I have a document containing nested array data. I tried hopelessly to filter the data using $elemMatch but I cannot figure out why it is not working.

{
'id' : 1,
'name' : 'test',
'modules' : [
    {
        name: 'foo',
        mandatory: false,
        group: [
            {
                name: g1
            }]
    },
    {
        name: 'bar',
        mandatory: false,
        group: [
            {
                name: g2
            }]
    }]
}

I tried using this query:

db.test.find(
{
  modules: {
            $elemMatch: {
                 name: "foo",
            }
  }
}

But it keeps returning all the modules. If I use mandatory: true it returns nothing, which seems to indicates it works. Any idea what am I doing wrong? Thanks!

like image 842
Phil Avatar asked Dec 11 '13 17:12

Phil


People also ask

How do I query nested data in MongoDB?

Accessing embedded/nested documents – In MongoDB, you can access the fields of nested/embedded documents of the collection using dot notation and when you are using dot notation, then the field and the nested field must be inside the quotation marks.

How do you match an array element in MongoDB?

The $elemMatch operator matches documents that contain an array field with at least one element that matches all the specified query criteria. If you specify only a single <query> condition in the $elemMatch expression, and are not using the $not or $ne operators inside of $elemMatch , $elemMatch can be omitted.

What is the use of elemMatch in MongoDB?

The $elemMatch Operator of the MongoDB is used to find documents with at least one array field. The finding operation matches the data in the array field with the criteria mentioned with the $elemMatch. $elemMatch is an operator by MongoDB that is used to match elements in an array.

How do I query an array of objects in MongoDB?

To search the array of object in MongoDB, you can use $elemMatch operator. This operator allows us to search for more than one component from an array object.


1 Answers

Your query is simply returning all docs that contain a modules element where name == 'foo'. To use $elemMatch to filter the output, you need to use it in the projection argument of the find call instead of part of the query:

db.test.find({}, {modules: {$elemMatch: {name: 'foo'}}})

To combine both concepts, you can reference the index of the array element matched in the query with $:

db.test.find({modules: {$elemMatch: {name: 'foo'}}}, {'modules.$': 1})

Either way returns:

{
  "_id": ObjectId("..."),
  "modules": [
    {
      "name": "foo",
      "mandatory": false,
      "group": [
        {
          "name": "g1"
        }
      ]
    }
  ]
}

If you need other fields included in the output, add them to the projection object (e.g. name: 1).

like image 72
JohnnyHK Avatar answered Oct 04 '22 13:10

JohnnyHK