【问题标题】:Return only matched sub-document elements within a nested array of references仅返回嵌套引用数组中匹配的子文档元素
【发布时间】:2018-05-27 12:59:31
【问题描述】:

我有一个名为 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 阻止我在 $eq 表达式中比较 $id。有人提到使用 $objectToArray 作为 hack,但我无法将其全部完成。

任何帮助将不胜感激。

【问题讨论】:

    标签: mongodb aggregation-framework


    【解决方案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")
            ]
        }
     ]
    }
    

    【讨论】:

      【解决方案2】:

      您可以使用下面的$project 阶段来比较 dbref id。

      $objectToArray 将 DBRef 转换为键值对。

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

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

      最后一步是通过使用 $in 表达式将传入的 ObjectId 值与 referencedMany id 值进行比较,得到 $filter "embeddedMany" 数组。

      {"$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
                    ]
                  }
                }
              }
            ]
          }
        }
       }
      }}
      

      【讨论】:

      • 天啊,这很复杂。非常感谢您的帮助。我需要深入研究它才能理解它。
      • 我很抱歉。我把它弄得不必要地复杂了。现已重构。
      猜你喜欢
      • 2016-07-13
      • 2020-12-11
      • 2019-01-16
      • 2019-04-23
      • 2019-02-16
      • 2021-05-01
      • 2016-10-31
      • 1970-01-01
      • 2018-08-16
      相关资源
      最近更新 更多