I'm trying to find all elements within an array called programme
. The result of running db.base.find({"programme.title":"News"},{"programme.$.title":"News"}).pretty()
is:
{
"_id" : ObjectId("55a48dd3e72db9d63e53478b"),
"programme" : [
{
"attributes" : {
"start" : "20150713010000 -0400",
"stop" : "20150713013000 -0400",
"channel" : "I47176.labs.zap2it.com"
},
"title" : "News",
"category" : "News",
"episode-num" : "SH01831861.0000",
"new" : true
}
]
}
But there are many more entries called "News", not just one, as shown above.
I've also tried db.base.find({"programme.title":"News"}).pretty()
but that just results in listing a bunch of random entries, whether or not they have the title of "News".
Thanks a lot for the help, and obligatory "apologies for noob question".
You can achieve with the help of Aggregation as below :
db.base.aggregate([
{$unwind : "$programme"},
{$match : { "programme.title" : "News" } },
{$group : { "_id" : "$_id" , "programme" : { $push: "$programme" } } }
]);
Projection to a match in MongoDB .find()
queries can only return the "first" element matching your conditions.
So to get "multiple" matches your best approach is using .aggregate()
and $redact
, with first filtering the documents with $match
:
db.base.aggregate([
{ "$match": { "programme.title":"News" } },
{ "$redact": {
"$cond": {
"if": { "$eq": [ { "$ifNull": [ "$title", "News" ] }, "News" } ],
"then": "$$DESCEND",
"else": "$$PRUNE"
}}
}}
])
This "removes" ("redacts") any entries from the array that do not match the "title" you are giving.
This is a good approach since you are not creating more documents in the pipeline using $unwind
, which is another way to work with arrays.
The catch is that you cannot have another element in your document with the same property name "title", as the $$DECEND
walks into the structure and compares the field names at each level.