【问题标题】:MongoDB Deep Link and Filter Children at the same timeMongoDB Deep Link 和 Filter Children 同时
【发布时间】:2021-07-07 23:41:40
【问题描述】:

我的目标是根据我输入的对象的根名称返回一个完全链接的对象,同时过滤“子子对象”。

所以给出下面的示例架构:

1.根对象集合

[
  {
     "_id": ObjectId("AAA1"),
     "name": "rootObj1",
     "subObjects": [ ObjectId("BBB1"), ObjectId("BBB2") ]
  },
  {
     "_id": ObjectId("AAA2"),
     "name": "rootObj2",
     "subObjects": []
  }
]

2。子对象集合

[
  {
     "_id": ObjectId("BBB1"),
     "name": "subObjectName1",
     "subSubObjects": [ ObjectId("CCC1"), ObjectId("CCC2") ]
  },
  {
     "_id": ObjectId("BBB2"),
     "name": "subObjectName2",
     "subSubObjects": [ ObjectId("CCC2") ]
  }
]

3.子子对象集合

[
  {
     "_id": ObjectId("CCC1"),
     "name": "nameToFind"
  },
  {
     "_id": ObjectId("CCC2"),
     "name": "someOtherName"
  }
]

如果我传入我想要“rootObj1”并且我只想要名称为“nameToFind”的子子对象(或类似于下面的内容,我不在乎是否_id 仍然在对象中,只是事物链接在一起的想法)

目标结果

{
  "name": "rootObj1",
  "subObjects": [
    {
      "name": "subObjectName1",
      "subSubObjects": [
        {"name": "nameToFind"}
      ]
    },
    {
      "name": "subObjectName2",
      "subSubObjects": []
    }
  ]
}

我发现很多有用的帖子展示了 $lookup、$unwind、$lookup(使用管道功能),然后使用组/项目或其他东西来组装它。虽然我可以使用查找来查找值,但我最终会得到类似下面的内容并且无法组装它。

所以我试图运行这样的东西:

rootCollection.aggregate([
    { "$match": {
        "name" : "rootObject1",
    }},
    { "$lookup": {
              "from": "subObject",
              "localField": "subObjects",
              "foreignField": "_id",
              "as": "subObjects"
            }
    },
    { "$lookup": {
                  "from": "subSubObjects",
                  "localField": "subObjects.subSubObjects",
                  "foreignField": "_id",
                  "as": "subSubObjects"
                }
    },
])

最终结果如下所示,但我真的不明白如何过滤 subSubObjects,然后以某种方式将它们重新合并到一个结构中。

[
  {
    "_id": {"$oid": "AAA1"},
    "name": "rootObject1",
    "subObjects": [ {"$oid": "BBB1")}, {"$oid": "BBB2")} ]
  },
  "subObjects": [
     {
        "_id": {"$oid": "BBB1"},
        "name": "subObjectName1",
        "subSubObjects": [ {"$oid": "CCC1")}, {"$oid": "CCC2")}) ]
     },
     {
        "_id": {"$oid": "BBB2"},
        "name": "subObjectName2",
        "subSubObjects": [ {"$oid": "CCC1")}, {"$oid": "CCC2")}) ]
     },
  ],
  "subSubObjects": [
     {
        "_id": {"$oid": "CCC1"},
        "name": "nameToFind",
     },
     {
        "_id": {"$oid": "CCC2"},
        "name": "someOtherName",
     },
  ]
]

【问题讨论】:

  • 这能回答你的问题吗? MongoDB nested lookup with 3 levels
  • 那种?这绝对有帮助。我觉得我需要滥用组运算符,因为我将“_id”设置为 {“rootObject”:{“subObjects”:“$subObjects”}} 等。让所有收集。因为我并不是真的想把任何事情总结在一起。我主要担心的是,随着我的真实数据结构的复杂性增加,这将变得难以管理。
  • 我剩下的主要问题是,当我深入到子子对象时,我将如何进行过滤,因为 $group 或 $lookup 都没有过滤。
  • 从重复的问题中查看这个answer,并查看您的问题的工作playground,当您使用管道查找时,不需要$group 阶段。
  • 我不知道您可以像这样在管道字段中进行查找。我试图连续进行一堆查找,然后稍后神奇地对它们进行分组。

标签: mongodb mongodb-query aggregation-framework


【解决方案1】:

有一个类似的question,我会从那个问题中推荐这个answer,但是字段的类型和结构略有不同,

你可以使用$lookup with aggregation pipeline,

  • $match你的条件
  • $lookup 与集合 2 中的管道并通过 subObjects 作为 let
  • $match,使用表达式检查$in 条件
  • $lookup 与集合 3 的简单连接,将 subSubObjects 作为 localField 传递,它会默认检查 $in 条件,因为 subSubObjects 是一个数组。
db.col1.aggregate([
  { "$match": { "name": "rootObj1" } },
  {
    $lookup: {
      from: "col2",
      let: { subObjects: "$subObjects" },
      pipeline: [
        {
          $match: { $expr: { $in: ["$_id", "$$subObjects"] } }
        },
        {
          $lookup: {
            from: "col3",
            localField: "subSubObjects",
            foreignField: "_id",
            as: "subSubObjects"
          }
        }
      ],
      as: "subObjects"
    }
  }
])

Playground

【讨论】:

  • 再次感谢!我假设如果我想过滤最终结果中返回的 subSubObjects,我需要在查找之后添加另一个管道匹配器?
  • 是的,或者您可以再次将 $lookup 与管道一起使用,并放置 $match 阶段而不是简单的查找。
猜你喜欢
  • 2020-12-24
  • 2022-08-19
  • 1970-01-01
  • 2021-02-17
  • 1970-01-01
  • 2015-12-30
  • 1970-01-01
  • 2021-09-26
  • 1970-01-01
相关资源
最近更新 更多