要做一些标准操作员不能立即提供的更详细的条件,那么最好的方法是使用聚合框架 . 这允许您进行一些处理以处理我们的条件,例如匹配的数量:
db.collection.aggregate([
// Filter the documents that are possible matches
{ "$match": {
"orgRoles": {
"$elemMatch": {
"app": "ANGRYBIRDS", "orgId": "CODOE"
}
}
}},
// De-normalize the array content
{ "$unwind": "$orgRoles" },
// Group and count the matches
{ "$group": {
"_id": "$_id",
"orgRoles": { "$push": "$orgRoles" },
"matched": {
"$sum": {
"$cond": [
{ "$eq": ["$orgRoles.app", "ANGRYBIRDS"] },
1,
0
]
}
}
}},
// Filter where matched is more that 1
{ "$match": {
"orgRoles": {
"$elemMatch": {
"app": "ANGRYBIRDS", "orgId": "CODOE"
}
},
"matched": 1
}},
// Optionally project to just keep the original fields
{ "$project": { "orgRoles": 1 } }
])
这里的主要事情发生在处理初始$match之后,只返回那些至少有一个数组元素与主条件匹配的文档,然后用$unwind处理数组元素后,可以单独检查它们 .
诀窍是使用$cond运算符的条件$sum操作,它是"ternary" . 这会在数组中找到"howMany"匹配到"ANGRYBIRDS"字符串 . 在此之后,您再次 $match 以便"filter"任何匹配计数超过一个的文档 . 仍然留在那里的其他条件,但这是没有必要的 .
只是为了记录,这也可以使用$where子句的JavaScript评估,但由于它可能在处理时效率不高:
db.collection.find({
"orgRoles": {
"$elemMatch": {
"app": "ANGRYBIRDS", "orgId": "CODOE"
}
},
"$where": function() {
var orgs = this.orgRoles.filter(function(el) {
return el.app == "ANGRYBIRDS";
});
return ( orgs.length == 1 );
}
})