Reputation: 715
Can anyone offer advice on how I would return a subset of array items? For example, let's suppose I have a collection of documents (similar to the example below) that contains a simple _id key and a key that contains an array of objects.
I would like to find all _id's and the matching objects that match a simple criteria:
// campaigns
{
"_id" : "Fred's C25K",
"campaignData" : [
{
"date" : "2015-06-17",
"source" : "nike"
},
{
"date" : "2015-06-17",
"source" : "reebok",
},
{
"date" : "2015-06-12",
"source" : "nike"
},
{
"date" : "2015-06-14",
"source" : "adidas"
},
]
},
{
"_id" : "Mike's Marathon",
"campaignData" : [
{
"date" : "2015-06-17",
"source" : "nike"
}
]
},
{
"_id" : "Jacob's Jamboree",
"campaignData" : [
{
"date" : "2015-06-17",
"source" : "keen"
}
]
}
I would like my result to contain the _id and any matching objects for, say, a date value of "2015-06-17"
// GOAL => To generate a result set that looks like:
{
"_id" : "Fred's C25K",
"campaignData" : [
{
"date" : "2015-06-17",
"source" : "nike"
},
{
"date" : "2015-06-17",
"source" : "reebok",
}
]
},
{
"_id" : "Mike's Marathon",
"campaignData" : [
{
"date" : "2015-06-17",
"source" : "nike"
}
]
},
{
"_id" : "Jacob's Jamboree",
"campaignData" : [
{
"date" : "2015-06-17",
"source" : "keen"
}
]
}
Upvotes: 6
Views: 924
Reputation: 103365
Use the aggregation framework to achieve the desired result. The following pipeline consists of a $match
operator stage as the first step to filter the documents that should pass through the pipeline.
The next stage is the $addFields
operator that allows you to output documents that contain all existing fields from the input documents and newly added fields.
Within this step you can use the $filter
operator to select a subset of an array to return based on the specified filter:
db.collection.aggregate([
{ "$match": {
"campaignData.date" : "2015-06-17"
} },
{ "$addFields": {
"campaignData": {
"$filter": {
"input": "$campaignData",
"cond": {
"$eq": ["$$this.date", "2015-06-17"]
}
}
}
} }
])
Result:
/* 0 */
{
"result" : [
{
"_id" : "Mike's Marathon",
"campaignData" : [
{
"date" : "2015-06-17",
"source" : "nike"
}
]
},
{
"_id" : "Jacob's Jamboree",
"campaignData" : [
{
"date" : "2015-06-17",
"source" : "keen"
}
]
},
{
"_id" : "Fred's C25K",
"campaignData" : [
{
"date" : "2015-06-17",
"source" : "nike"
},
{
"date" : "2015-06-17",
"source" : "reebok"
}
]
}
],
"ok" : 1
}
Upvotes: 3