In this question, Jeff the Bear explained how to search documents with an array
contains 'tag1'
contains ['tag1','tag2'],
contains any of ['tag3', 'tag4']
But how should I do if I want to search documents with an array which is part of another array?
post1.tags = ['tag1']
post2.tags = ['tag1','tag3']
post3.tags = ['tag2','tag4']
post4.tags = ['tag1','tag2','tag3','tag4']
I want to get post1 and post3 because they have tags
contained in ['tag1', 'tag2', 'tag4']
I don't want to get post2 and post4, because tag3 doesn't exist in ['tag1', 'tag2', 'tag4']
In other words, select posts that all elements in its tags array can be found in another conditional array
You can use aggregation framework to do this. Given the following data
> db.post.find()
{ "_id" : 1, "tags" : [ "tag1" ] }
{ "_id" : 2, "tags" : [ "tag1", "tag3" ] }
{ "_id" : 3, "tags" : [ "tag2", "tag4" ] }
{ "_id" : 4, "tags" : [ "tag1", "tag2", "tag3", "tag4" ] }
the aggregation query
db.post.aggregate({
$project: {
_id: 1,
tags: 1,
killFlag: {
$const: [true, false]
}
}
}, {
$unwind: "$tags"
}, {
$unwind: "$killFlag"
}, {
$match: {
$nor: [{
tags: {
$in: ['tag1', 'tag2', 'tag4']
},
killFlag: true
}
]
}
}, {
$group: {
_id: "$_id",
tags: {
$addToSet: "$tags"
},
killFlag: {
$max: "$killFlag"
}
}
}, {
$match: {
killFlag: false
}
}, {
$project: {
_id: 1,
tags: 1
}
})
would give you
{
"result": [{
"_id": 3,
"tags": [
"tag4",
"tag2"
]
}, {
"_id": 1,
"tags": [
"tag1"
]
}
],
"ok": 1
}