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?
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.
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.
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.
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.
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" } ] } ]
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 }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With