仅返回嵌套引用数组中匹配的子文档元素

时间:2017-12-13 15:12:33

标签: mongodb aggregation-framework

我有一个名为Container的集合,其中包含一组名为embeddedMany的嵌入式文档。每个嵌入的文档都引用了几个名为Referenced的其他文档,这些引用存储在名为referenceMany的数组中。该文件看起来像这样。

{ 
    "_id" : ObjectId("5a312337ea5cb32d30005d25"), 
    "embeddedMany" : [
        {
            "referencedMany" : [
                DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d24"), "myDb"),
                DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d23"), "myDb")
            ]
        }, 
        {
            "referencedMany" : [
                DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d23"), "myDb")
                DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d22"), "myDb")
            ]
        },
        {
            "referencedMany" : [
                DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d24"), "myDb")
                DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d22"), "myDb")
            ]
        }
    ], 
}

现在我需要查找引用某些文档的所有嵌入式文档。让我们说一下:DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d22"), "myDb")

我需要生成的文档如下所示:

{ 
    "_id" : ObjectId("5a312337ea5cb32d30005d25"), 
    "embeddedMany" : [
        {
            "referencedMany" : [
                DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d23"), "myDb")
                DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d22"), "myDb")
            ]
        },
        {
            "referencedMany" : [
                DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d24"), "myDb")
                DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d22"), "myDb")
            ]
        }
    ], 
}

我读了this非常相似的问题。所以我想我需要使用聚合并过滤embeddedMany字段。到目前为止,我的聚合看起来像这样:

db.Container.aggregate(
    [
        {
            $match: {
                "embeddedMany.referencedMany.$id": ObjectId("5a312337ea5cb32d30005d22")
            }
        },
        {
            $project: {
                "embeddedMany": {
                    "$filter": {
                        "input": "$embeddedMany",
                        "as": "embedded",
                        "cond": {
                            "$eq": [
                                "$$embedded.referencedMany.$id",
                                ObjectId("5a312337ea5cb32d30005d22")
                            ]
                        }
                    }
                }
            }
        },
    ]
);

这就是我撞墙的地方。因为MongoDB有outstanding bug阻止我比较$id表达式中的$eq。有一些提到使用$objectToArray作为黑客,但我无法将它们全部拉开。

任何帮助都将受到高度赞赏。

2 个答案:

答案 0 :(得分:1)

您可以使用以下$project阶段来比较dbref ID。

$objectToArray将DBRef转换为键值对。

下一步是$filter dbref键值对只包含id键值对。

$let + $map表达式的下一步,仅投影id值。

最后一步是$filter" embeddedMany"数组通过使用$in表达式将ObjectId值中的传递与引用的多数用户值进行比较。

{"$project":{"embeddedMany":{
  "$filter":{
    "input":"$embeddedMany",
    "as":"embedded",
    "cond":{
      "$in":[
        ObjectId("5a312337ea5cb32d30005d22"),
        {
          "$map":{
            "input":"$$embedded.referencedMany",
            "as":"referenced",
            "in":{
              "$arrayElemAt":[
                {
                  "$let":{
                    "vars":{
                      "id":{
                        "$filter":{
                          "input":{"$objectToArray":"$$referenced"},
                          "as":"r",
                          "cond":{"$eq":["$$r.k",{"$literal":"$id"}]}
                        }
                      }
                    },
                    "in":"$$id.v"
                  }
                },
                0
              ]
            }
          }
        }
      ]
    }
  }
 }
}}

答案 1 :(得分:1)

如果您想要的结果与您提供的示例相似,则无需分解对象,也不必担心引用的错误。只需在管道中的DBRef对象之间进行比较(例如在mongo shell中完成:

mydbref = DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d22"), "myDb");
db.dbref.aggregate([
   {$match:{"embeddedMany.referencedMany":mydbref}}, 
   {"$project":{"embeddedMany":{
     "$filter":{
       "input":"$embeddedMany",
       "cond":{
          "$in":[{$literal:mydbref},"$$this.referencedMany"]
       }
     }
   }}}
])
{
 "_id" : ObjectId("5a312337ea5cb32d30005d25"),
 "embeddedMany" : [
    {
        "referencedMany" : [
            DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d23"), "myDb"),
            DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d22"), "myDb")
        ]
    },
    {
        "referencedMany" : [
            DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d24"), "myDb"),
            DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d22"), "myDb")
        ]
    }
 ]
}