Reputation: 6497
I have a query that returns objects containing an array of objects. Within that array of objects, there are some that should not be processed. Here is an object simmilar to what I have:
{
_id: 12345,
data: [
{
state: 1,
info: "abc"
},{
state: 2,
info: "cde"
},{
state: 2,
info: "efg"
}
]
}
I want to show only the objects where state does not equal to 1. So I want to get back something like this:
{
_id: 12345,
data: [
{
state: 2,
info: "cde"
},{
state: 2,
info: "efg"
}
]
}
There can be hundreds of "main" objects with tens of "sub" objects. I tried using the query:
col.find({'data.info': {$in: [] }, {_id: 1, data: { $elemMatch: { state: {$ne: 1 } } } }, {}, callback);
But that only gives me this:
{
_id: 12345,
data: [
{
state: 2,
info: "cde"
}
]
}
In other words, $elemMatch does what it is supposed to do, but I need to get a different result. So is there a way to do that in one query or without pre-processing results (removing entries before any further code reads the data)?
Upvotes: 0
Views: 653
Reputation: 65443
The $elemMatch
projection operator only returns the first matching element in an array.
To filter the whole array, the best approach in MongoDB 2.2+ would be using the Aggregation Framework. Alternative, you could also do this using Map/Reduce or in your application code.
Example aggregation:
db.data.aggregate(
// Initial match to limit number of documents
{ $match : {
data: { $elemMatch: { state: {$ne: 1 } } }
}},
// Convert the data array into a stream of documents
{ $unwind: "$data" },
// Limit to matching elements of the data array
{ $match : {
"data.state": {$ne: 1 }
}},
// Re-group by original document _id
{ $group: {
_id: "$_id",
data: { $push: "$data" }
}}
)
Sample output:
{
"_id" : 12345,
"data" : [
{
"state" : 2,
"info" : "cde"
},
{
"state" : 2,
"info" : "efg"
}
]
}
Upvotes: 1