$ ElemMatch not working with new mongodb 2.2?

In the new version on MongoDB, we can use the $ elemMatch projection operator to limit the response of the request to one corresponding element of the array. http://docs.mongodb.org/manual/reference/projection/elemMatch/

But it doesn't seem to work in mongoose 3 yet, here is an example:

{ _id: ObjectId(5), items: [1,2,3,45,4,67,9,4] } Folder.findOne({_id: Object(5)}, {$elemMatch: {$in: [1,67,9]}}) .exec(function (err, doc) { }); 

I expect to receive the following document:

 { _id: ObjectId(5), items: [1,67,9] } 

But, unfortunately, I get a document with all the elements:

 { _id: ObjectId(5), items: [1,2,3,45,4,67,9,4] } 
+4
source share
4 answers

The mongodb docs are misleading here, we will update them.

As they say, now you can use $ elemMatch in your projection, i.e. your field selection:

https://gist.github.com/3640687

See also: https://github.com/learnboost/mongoose/issues/1085

[Edit] traction request for submitted documents: https://github.com/mongodb/docs/pull/185

+4
source

First, you are missing the name of the items field before the $ elemMatch statement. Your request must read

 Folder.findOne({_id: Object(5)}, {items: {$elemMatch: {$in: [1,67,9]}}}) .exec(function (err, doc) { }); 

But this still will not return the desired result, because, as indicated in the documentation:

The projection $ elemMatch will correspond to only one element of the array per source document.

So, you only get something like:

 { _id: ObjectId(5), items: [1] } 
+2
source

I don't have a mongoose setting to do this with node, but you can also get the result you want to use in the new aggregation structure in 2.2 - here is an example that gives you the result you wanted. Firstly, my doc example is as follows:

 > db.foo.findOne() { "_id" : ObjectId("50472eb566caf6af6108de02"), "items" : [ 1, 2, 3, 45, 4, 67, 9, 4 ] } 

To get what you want, I did this:

 > db.foo.aggregate( {$match : {"_id": ObjectId("50472eb566caf6af6108de02")}}, {$unwind : "$items"}, {$match : {"items": {$in : [1, 67, 9]}}}, {$group : {_id : "$_id", items : { $push : "$items"}}}, {$project : {_id : 0, items : 1}} ) { "result" : [ { "_id" : ObjectId("50472eb566caf6af6108de02"), "items" : [ 1, 67, 9 ] } ], "ok" : 1 } 

To explain, in detail I will take it line by line:

 {$match : {"_id": ObjectId("50472eb566caf6af6108de02")}} 

This is pretty obvious - this is basically the equivalent of regular search criteria, the results are passed to the next step in the pipeline that needs to be processed. This is the part that can use indexes, etc.

 {$unwind : "$items"} 

This will cause the array to explode, creating a stream of documents, one for each element in the array.

 {$match : {"items": {$in : [1, 67, 9]}}} 

This second match returns only the documents in the list, basically reducing the flow of documents to a set of three results.

 {$group : {_id : "$_id", items : { $push : "$items"}}} 

We want our output to be an array, so we must cancel the cancellation above when we have selected the elements we need, using _id as the key to the group. Note: if you match again, the values ​​will be repeated if you need a unique list that you would use $addToSet instead of $push

 {$project : {_id : 1, items : 1}} 

Then, finally, this projection is really not needed, but I turned it on to illustrate the functionality - you could not return _id if you want, etc.

+1
source

Not a single element of $ elemMatch or MongoDB will filter data from the array at all. $ elemMatch can be used to match the document, but this will not affect the returned data. You can only include / exclude fields from the document using the filter parameter (the second parameter of the find () findOne () call), but you cannot filter the result based on some query input.

-1
source

Source: https://habr.com/ru/post/1432407/


All Articles