Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find in Double Nested Array MongoDB

I have this Collection in mongodb

{ "_id" : "777", "someKey" : "someValue", "someArray" : [     {         "name" : "name1",         "someNestedArray" : [             {                 "name" : "value"             },             {                 "name" : "delete me"             }         ]     }   ] } 

I want to find document based on someArray.someNestedArray.name but i can't find any useful link all search result about update nested array i am trying this but return nothing

db.mycollection.find({"someArray.$.someNestedArray":{"$elemMatch":{"name":"1"}}}) db.mycollection.find({"someArray.$.someNestedArray.$.name":"1"}) 

and Some thing else

how can i find by element in double nested array mongodb?

like image 282
Ali Kianinejad Avatar asked Mar 16 '15 07:03

Ali Kianinejad


People also ask

Where can I find nested documents 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 I search an array 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.

How do I use elemMatch 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.


1 Answers

In the simplest sense this just follows the basic form of "dot notation" as used by MongoDB. That will work regardless of which array member the inner array member is in, as long as it matches a value:

db.mycollection.find({     "someArray.someNestedArray.name": "value" }) 

That is fine for a "single field" value, for matching multiple-fields you would use $elemMatch:

db.mycollection.find({     "someArray": {          "$elemMatch": {             "name": "name1",             "someNestedArray": {                 "$elemMatch": {                     "name": "value",                     "otherField": 1                 }             }         }     } }) 

That matches the document which would contain something with a a field at that "path" matching the value. If you intended to "match and filter" the result so only the matched element was returned, this is not possible with the positional operator projection, as quoted:

Nested Arrays

The positional $ operator cannot be used for queries which traverse more than one array, such as queries that traverse arrays nested within other arrays, because the replacement for the $ placeholder is a single value

Modern MongoDB

We can do this by applying $filter and $map here. The $map is really needed because the "inner" array can change as a result of the "filtering", and the "outer" array of course does not match the conditions when the "inner" was stripped of all elements.

Again following the example of actually having multiple properties to match within each array:

db.mycollection.aggregate([   { "$match": {     "someArray": {       "$elemMatch": {          "name": "name1",          "someNestedArray": {            "$elemMatch": {              "name": "value",              "otherField": 1            }          }        }     }   }},   { "$addFields": {     "someArray": {       "$filter": {         "input": {           "$map": {             "input": "$someArray",             "as": "sa",             "in": {               "name": "$$sa.name",               "someNestedArray": {                 "$filter": {                   "input": "$$sa.someNestedArray",                   "as": "sn",                   "cond": {                     "$and": [                       { "$eq": [ "$$sn.name", "value" ] },                       { "$eq": [ "$$sn.otherField", 1 ] }                     ]                   }                 }               }                          }           },         },         "as": "sa",         "cond": {           "$and": [             { "$eq": [ "$$sa.name", "name1" ] },             { "$gt": [ { "$size": "$$sa.someNestedArray" }, 0 ] }           ]         }       }     }   }} ]) 

Therefore on the "outer" array the $filter actually looks at the $size of the "inner" array after it was "filtered" itself, so you can reject those results when the whole inner array does in fact match noting.

Older MongoDB

In order to "project" only the matched element, you need the .aggregate() method:

db.mycollection.aggregate([     // Match possible documents     { "$match": {         "someArray.someNestedArray.name": "value"     }},      // Unwind each array     { "$unwind": "$someArray" },     { "$unwind": "$someArray.someNestedArray" },      // Filter just the matching elements     { "$match": {         "someArray.someNestedArray.name": "value"     }},      // Group to inner array     { "$group": {         "_id": {              "_id": "$_id",              "name": "$someArray.name"         },         "someKey": { "$first": "$someKey" },         "someNestedArray": { "$push": "$someArray.someNestedArray" }     }},      // Group to outer array     { "$group": {         "_id": "$_id._id",         "someKey": { "$first": "$someKey" },         "someArray": { "$push": {             "name": "$_id.name",             "someNestedArray": "$someNestedArray"         }}     }}  ]) 

That allows you to "filter" the matches in nested arrays for one or more results within the document.

like image 104
Neil Lunn Avatar answered Sep 23 '22 17:09

Neil Lunn