On Mongo 2.4.6
Collection of Users
{
"_id" : User1,
"orgRoles" : [
{"_id" : 1, "app" : "ANGRYBIRDS", "orgId" : "CODOE"},
{"_id" : 2, "app" : "ANGRYBIRDS", "orgId" : "MSDN"}
],
},
{
"_id" : User2,
"orgRoles" : [
{"_id" : 1, "app" : "ANGRYBIRDS", "orgId" : "CODOE"},
{"_id" : 2, "app" : "HUNGRYPIGS", "orgId" : "MSDN"}
],
},
{
"_id" : User2,
"orgRoles" : [
{"_id" : 1, "app" : "ANGRYBIRDS", "orgId" : "YAHOO"},
{"_id" : 2, "app" : "HUNGRYPIGS", "orgId" : "MSDN"}
],
}
使用如上所示的数据,我正在尝试编写一个查询来获取:
只有一个ANGRYBIRDS应用程序和ANGRYBIRDS应用程序的用户的所有ID都在CODOE组织中。
因此它会返回User2,因为它们有1个ANGRYBIRDS并且在ORG“CODOE”中而不是User1,因为它们有两个ANGRYBIRDS或User3,因为它们在“CODOE”组织中没有ANGRYBIRDS应用程序。我对mongo查询相当新,所以任何帮助都表示赞赏。
答案 0 :(得分:1)
要做一些标准操作员不能立即提供的更详细的条件,那么最好的方法是使用聚合框架。这允许您进行一些处理以处理我们的条件,例如匹配的数量:
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
处理数组元素之后它们可以单独检查。
技巧是使用$sum
运算符的条件$cond
操作,这是一个“三元”运算符。这会将数组中的“howMany”匹配评估为“ANGRYBIRDS”字符串。在此之后,您再次 $match
,以便“过滤”匹配计数超过一个的任何文档。仍然留下其他条件,但这确实没有必要。
仅仅为了记录,使用$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 );
}
})
答案 1 :(得分:0)
使用aggregation pipeline
执行此操作的一种方法是:
db.users.aggregate([
// Match the documents with app being "ANGRYBIRDS" and orgID being "CODE"
// Note that this step filters out most of the documents and is good to have
// at the start of the pipeline, moreover it can make use of indexes, if
// used at the beginning of the aggregation pipeline.
{
$match : {
"orgRoles.app" : "ANGRYBIRDS",
"orgRoles.orgId" : "CODOE"
}
},
// unwind the elements in the orgRoles array
{
$unwind : "$orgRoles"
},
// group by userid and app
{
$group : {
"_id" : {
"id" : "$_id",
"app" : "$orgRoles.app"
},
// take the id and app of the first document in each group, since all
// the
// other documents in the group will have the same values.
"id" : {
$first : "$_id"
},
"app" : {
$first : "$orgRoles.app"
},
// orgId can be different, so form an array for each group.
"orgId" : {
$push : {
"id" : "$orgRoles.orgId"
}
},
// count the number of documents in each group.
"count" : {
$sum : 1
}
}
},
// find the matching group
{
$match : {
"count" : 1,
"app" : "ANGRYBIRDS",
"orgId" : {
$elemMatch : {
"id" : "CODOE"
}
}
}
},
// project only the userid
{
$project : {
"id" : 1,
"_id" : 0
}
} ]);
编辑:已删除映射聚合结果,因为问题需要v2.4.6中的解决方案,并且根据文档。
在2.6版中更改:db.collection.aggregate()方法返回一个游标,可以返回任何大小的结果集。之前的版本 将所有结果返回到单个文档中,结果集为 受限制为16兆字节。