Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Retrieve only the queried element in an object array in MongoDB collection

Suppose you have the following documents in my collection:

{      "_id":ObjectId("562e7c594c12942f08fe4192"),    "shapes":[         {            "shape":"square",          "color":"blue"       },       {            "shape":"circle",          "color":"red"       }    ] }, {      "_id":ObjectId("562e7c594c12942f08fe4193"),    "shapes":[         {            "shape":"square",          "color":"black"       },       {            "shape":"circle",          "color":"green"       }    ] } 

Do query:

db.test.find({"shapes.color": "red"}, {"shapes.color": 1}) 

Or

db.test.find({shapes: {"$elemMatch": {color: "red"}}}, {"shapes.color": 1}) 

Returns matched document (Document 1), but always with ALL array items in shapes:

{ "shapes":    [     {"shape": "square", "color": "blue"},     {"shape": "circle", "color": "red"}   ]  } 

However, I'd like to get the document (Document 1) only with the array that contains color=red:

{ "shapes":    [     {"shape": "circle", "color": "red"}   ]  } 

How can I do this?

like image 711
Sebtm Avatar asked Oct 21 '10 07:10

Sebtm


People also ask

How do I pull an element from an array in MongoDB?

To remove an element, update, and use $pull in MongoDB. The $pull operator removes from an existing array all instances of a value or values that match a specified condition.

How do I filter an array of objects in MongoDB?

Suppose there is an index on some path in the array element. Use cond: { $eq: ['$$item. a', <value> ] } to filter elements based on exact equivalent values.

How retrieve data from collections in MongoDB?

You can use read operations to retrieve data from your MongoDB database. There are multiple types of read operations that access the data in different ways. If you want to request results based on a set of criteria from the existing set of data, you can use a find operation such as the find() or findOne() methods.

How do I find a specific value in MongoDB?

Find() Method. In MongoDB, find() method is used to select documents in a collection and return a cursor to the selected documents. Cursor means a pointer that points to a document, when we use find() method it returns a pointer on the selected documents and returns one by one.


2 Answers

MongoDB 2.2's new $elemMatch projection operator provides another way to alter the returned document to contain only the first matched shapes element:

db.test.find(     {"shapes.color": "red"},      {_id: 0, shapes: {$elemMatch: {color: "red"}}}); 

Returns:

{"shapes" : [{"shape": "circle", "color": "red"}]} 

In 2.2 you can also do this using the $ projection operator, where the $ in a projection object field name represents the index of the field's first matching array element from the query. The following returns the same results as above:

db.test.find({"shapes.color": "red"}, {_id: 0, 'shapes.$': 1}); 

MongoDB 3.2 Update

Starting with the 3.2 release, you can use the new $filter aggregation operator to filter an array during projection, which has the benefit of including all matches, instead of just the first one.

db.test.aggregate([     // Get just the docs that contain a shapes element where color is 'red'     {$match: {'shapes.color': 'red'}},     {$project: {         shapes: {$filter: {             input: '$shapes',             as: 'shape',             cond: {$eq: ['$$shape.color', 'red']}         }},         _id: 0     }} ]) 

Results:

[      {         "shapes" : [              {                 "shape" : "circle",                 "color" : "red"             }         ]     } ] 
like image 186
JohnnyHK Avatar answered Oct 18 '22 18:10

JohnnyHK


The new Aggregation Framework in MongoDB 2.2+ provides an alternative to Map/Reduce. The $unwind operator can be used to separate your shapes array into a stream of documents that can be matched:

db.test.aggregate(   // Start with a $match pipeline which can take advantage of an index and limit documents processed   { $match : {      "shapes.color": "red"   }},   { $unwind : "$shapes" },   { $match : {      "shapes.color": "red"   }} ) 

Results in:

{     "result" : [         {             "_id" : ObjectId("504425059b7c9fa7ec92beec"),             "shapes" : {                 "shape" : "circle",                 "color" : "red"             }         }     ],     "ok" : 1 } 
like image 40
Stennie Avatar answered Oct 18 '22 19:10

Stennie