Does $elemMatch not work with a new mongodb 2.2?

In a new version on MongoDB we can use an $elemMatch projection operator to limit the response of a query to a single matching element of an array. http://docs.mongodb.org/manual/reference/projection/elemMatch/

But it seems doesn't work yet in mongoose 3 here is the 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'm expected to get the follows doc:

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

But unfortunately what I'm getting is document with all items:

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

The mongodb docs here are misleading, we'll get them updated.

What its saying is that you can now use $elemMatch in your projection, that is, your field selection:

https://gist.github.com/3640687

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

[Edit] pull request for docs sent: https://github.com/mongodb/docs/pull/185

Firstly, you are missing the items field name in front of the $elemMatch operator. Your query should read

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

But this would still not return the desired result, because as stated in the documentation:

The $elemMatch projection will only match one array element per source document.

So you would only get back something like:

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

I haven't got mongoose set up to do this with node, but you can also get the result you want using the new aggregation framework in 2.2 - here's an example that gets you the result you wanted. First, my sample doc looks like this:

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

To get to 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 fairly obvious - it is basically the equivalent to the find criteria on a regular query, the results are passed to the next step in the pipeline to be processed. This is the piece that can use indexes etc.

{$unwind : "$items"}

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

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

This second match will return only the documents in the list, basically reducing the stream of docs to a result set of three.

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

We want our output to be an array, so we have to undo the unwind above now that we have selected the items we want, using the _id as the key to group. Note: this will have repeating values if there is more than one match, if you wanted a unique list you would use $addToSet instead of $push

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

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

Neither $elemMatch nor MongoDB in general will filter data from an array. $elemMatch can be used to match a document but it won't affect the data to be returned. You can only include/exclude fields from a documented by using the filter parameter (second parameter of a find() findOne() call) but you can not filter the result based on some query input.