MongoDB获取需要与同一集合中的其他文档进行比较的唯一文档

时间:2015-12-18 02:54:26

标签: mongodb mongodb-query

以下是我在测试集合中的示例文档结构。

问题描述:

我必须根据以下条件从此文档中获取name字段。

我会将role字段作为查询条件传递。它应该获取与文档中的name无关的role值。

请考虑以下文档。如果我的查询条件是角色r1,则查询查询应返回以下名称:

{"name":"S"},{"name":"G"}, {"name":"H"}

因为r1未在集合中的任何文档中分配给此名称。

同样的规则适用于r2r3 ... r7等所有角色。 所以基本上我们必须查找集合中的所有文档,并且需要获取未分配给任何组的名称。

/* 0 */
    {
        "_id" : ObjectId("567286bda5543ad892916a49"),
        "name" : "A",
        "role" : "r1"
    }

    /* 1 */
    {
        "_id" : ObjectId("567286bda5543ad892916a4a"),
        "name" : "A",
        "role" : "r2"
    }

    /* 2 */
    {
        "_id" : ObjectId("567286bda5543ad892916a4b"),
        "name" : "A",
        "role" : "r3"
    }

    /* 3 */
    {
        "_id" : ObjectId("567286bda5543ad892916a4c"),
        "name" : "B",
        "role" : "r2"
    }

    /* 4 */
    {
        "_id" : ObjectId("567286bda5543ad892916a4d"),
        "name" : "A",
        "role" : "r4"
    }

    /* 5 */
    {
        "_id" : ObjectId("567286bda5543ad892916a4e"),
        "name" : "B",
        "role" : "r1"
    }

    /* 6 */
    {
        "_id" : ObjectId("5672a8b7a5543ad892916a4f"),
        "name" : "S",
        "role" : "r3"
    }

    /* 7 */
    {
        "_id" : ObjectId("5672a8b7a5543ad892916a50"),
        "name" : "G",
        "role" : "r6"
    }

    /* 8 */
    {
        "_id" : ObjectId("5672a8b7a5543ad892916a51"),
        "name" : "H",
        "role" : "r2"
    }

预期产出:

-- input is role `r1` then (Need to show the name if `r1` is not associate already) -- same description for all the roles

    {"name" : "S"},
    {"name" : "G"},
    {"name" : "H"}

    -- input is role 'r2' then

    {"name" : "S"},
    {"name" : "G"}

    -- input is role 'r3' then

    {"name" : "B"},
    {"name" : "G"},
    {"name" : "H"}

    -- input is role 'r4' then

    {"name" : "B"},
    {"name" : "S"},
    {"name" : "G"},
    {"name" : "H"}

    -- input is role 'r6' then

    {"name" : "A"},
    {"name" : "B"},
    {"name" : "S"},
    {"name" : "H"}

非常感谢任何帮助。如何实现这个。aggregation框架或正常查找查询?请建议。

2 个答案:

答案 0 :(得分:1)

我找到了一种更好的方法来获得这个结果而不是被接受的答案,我认为性能会更好。看看吧:

 db.collection.aggregate([
{ 
                  $group: { _id: null,             
                      rightrole: { $addToSet:  { $cond : {if: { $ne: [ "$role", "r1" ] }, then: "$name", else: null }} }, 
                      wrongrole: { $addToSet:  { $cond : {if: { $eq: [ "$role", "r1" ] }, then: "$name", else: null } } } } 
                          }, 
          {   "$project": {"_id": 0,         
                         "name": { "$setDifference": [ "$rightrole", "$wrongrole" ] } }
},              {$unwind: "$name"}
]);
  1. 查找不在当前角色中的名称列表并添加它 到一个数组。
  2. 查找当前角色中的名称列表 并将其添加到数组中。
  3. 找出2个数组之间的差异 使用$ setDifference运算符。
  4. 放松名称

答案 1 :(得分:0)

您可以尝试使用聚合:

db.getCollection('roles').aggregate([
    {$group: {_id:"$name", "roles":{$addToSet:"$role"}}},
    {$project: {_id:1, "roles": 1, "isSubset": { $setIsSubset: [ ["r1"], "$roles" ] }}},
    {$match: {"isSubset": false}},
    {$group: {_id:"$isSubset", "name": {$push : "$_id"}}},
    {$project: {"_id": 0, "name": 1}},
    {$unwind: "$name"}
])
  1. 按名称分组,并将角色推送到数组中。
  2. 创建" isSubset"字段,表明您的角色"是roles数组"。
  3. 的子集
  4. 仅搜索那些" isSubset"字段是假的
  5. 分组" isSubset"
  6. 仅显示"名称"字段。
  7. 放松"名称"