Reputation: 14750
I have the following MongoDB document:
{
_id: ObjectId(5),
items: [1,2,3,45,4,67,9,4]
}
I need to fetch that document with filtered items (1, 9, 4)
result:
{
_id: ObjectId(5),
items: [1,9,4]
}
I've tried an $elemMatch projection but it returns only one item:
A.findById(ObjectId(5))
.select({ items: { $elemMatch: {$in: [1, 9, 4]}}})
.exec(function (err, docs) {
console.log(doc); // { _id: ObjectId(5), items: [ 1 ] }
done(err);
});
How can I get the document with items: 1, 9, 4 only?
Upvotes: 4
Views: 8459
Reputation: 65323
In modern versions of MongoDB (3.2+) you can use the $filter
operator to select a subset of an array field to return based on a specified condition. Returned elements will be in the original order from the field array.
Example in the mongo
shell:
db.items.aggregate([
{ $match : {
_id: 5
}},
{ $project: {
items: {
$filter: {
input: "$items",
cond: {
"$in": ["$$this", [1, 9, 4]]
}
}
}
}
}])
Note: because the original array in this question has the value 4
twice, the $filter
command will return both occurrences:
{ "_id" : 5, "items" : [ 1, 4, 9, 4 ] }
For an alternative approach which will only return the unique matching items, the $setIntersection
operator could be used:
db.items.aggregate([
{ $match : {
_id: 5
}},
{ $project: {
items: {
$setIntersection: ['$items', [1,4,9]]
}
}}
])
This will return: { "_id" : 5, "items" : [ 1, 4, 9 ] }
.
(original answer from September, 2012 below)
If you want the document manipulation to happen on the server side, you can use the Aggregation Framework in MongoDB 2.2:
db.items.aggregate(
// Match the document(s) of interest
{ $match : {
_id: 5
}},
// Separate the items array into a stream of documents
{ $unwind : "$items" },
// Filter the array
{ $match : {
items: { $in: [1, 9, 4] }
}},
// Group the results back into a result document
{ $group : {
_id: "$_id",
items: { $addToSet : "$items" }
}}
)
Result:
{
"result" : [
{
"_id" : 5,
"items" : [
9,
4,
1
]
}
],
"ok" : 1
}
Upvotes: 3
Reputation: 75666
Use underscore in your node.js app:
npm install underscore
var _ = require('underscore');
You can use the intersection function of arrays:
intersection_.intersection(*arrays)
Computes the list of values that are the intersection of all the arrays. Each value in the result is present in each of the arrays.
_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2]
http://documentcloud.github.com/underscore/#intersection
Upvotes: 0
Reputation: 6839
A.items = A.items.filter( function(i) {return i == 1 || i == 9 || i == 4} );
Upvotes: 4