【问题标题】:Mongodb lookup array of objects with 'let' variableMongodb 使用“let”变量查找对象数组
【发布时间】:2021-12-25 01:16:48
【问题描述】:

我需要将同一个表“实体”中的实体连接在一起。 本地键是本地实体的_id。 外键位于“rels”对象数组中(_id 存储在 rels.r 中)。

当我使用示例 _id 字符串测试 $match 时,查找工作正常。 但是当我尝试使用用'let'声明的变量时(应该使用相同的字符串,只是在一个变量中)它不起作用。

示例数据:

{ // PARENT ENTITY
  "_id":"123", // the local key
  "title":"initialentity",
},
{ // CHILD ENTITY 
  "_id":"456",
  "title":"relatedentity",
  "rels":[
    {
      "r":"123", // the foreign key
      "a":"exampledata-ignorethisfield",
    },
  ]
}

聚合:

[
  { "$lookup": {
    "from": "entities",
    "let": { "id": { $toString: "$_id" }  },
    // "let": { "id": "$_id"  }, // this alternative let doesn't work either
    "pipeline": [
      //{ "$match": { "rels.r": "123" } }, // This test works fine
      { "$match": { "rels.r": "$$id" } }, // But this, using the let variable, doesn't work
      {"$limit": 1}
    ],
    "as": "result"
  }},
  {"$limit": 1}
]

实际输出(结果数组为空):

{ 
  "_id":"123", // the local key
  "title":"initialentity",
  "results": []
},

预期输出(结果数组有相关对象):

{ 
  "_id":"123", // the local key
  "title":"initialentity",
  "results": [
    {
      "_id":"456",
      "title":"relatedentity",
      "rels":[
        {
          "r":"123", // the foreign key
          "a":"exampledata-ignorethisfield",
        },
      ]
    }
  ]
},

由于将添加其他条件,我需要它使用此方法(使用管道)。

提前感谢您的帮助。我确定我遗漏了一些明显的东西。我浏览了许多 SO qs 和 mongo 文档,但无法弄清楚这一点。 我也尝试过以下方法但没有成功:

{ "$match": { $expr: { "rels": {"r" : "$$id"} } } }, // This doesn't work (returns unrelated entities)
{ "$match": { $expr: { $eq: [ "rels.r" , "$$id" ] } } }, // This doesn't work (returns empty array)

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework


    【解决方案1】:

    您需要使用$expr,因为您已尝试按顺序使用to access the variable $$id,但您还需要在rels.r 前加上$,以便将rels.r 的值与@ 进行比较987654333@ 而不是文字字符串 "rels.r"

    [
      { "$lookup": {
        "from": "entities",
        "let": { "id": { $toString: "$_id" }  },
        "pipeline": [
          { "$match": { $expr: { $eq: [ "$rels.r" , "$$id" ] } } },
          { "$limit": 1 }
        ],
        "as": "result"
      }},
      { "$limit": 1 }
    ]
    

    编辑

    $eq 在匹配对象数组时似乎不起作用,我已经能够使用 $in 使其工作:

    [
      { "$lookup": {
        "from": "entities",
        "let": { "id": { $toString: "$_id" }  },
        "pipeline": [
          { "$match": { $expr: { $in: [ "$$id" , { $ifNull: [ "$rels.r", [] ] } ] } } },
          { "$limit": 1 }
        ],
        "as": "result"
      }},
      { "$limit": 1 }
    ]
    

    我选择包含$ifNull,因为如果第二个参数不解析为数组,$in 将失败,如果文档没有rels 字段,就会发生这种情况。如果每个文档确实都有一个rels 字段,请随意省略它,而只使用"$rels.r"

    Working MongoPlayground

    【讨论】:

    • 谢谢指正。不幸的是,它仍然返回一个空数组 (mongoplayground.net/p/dgF8We0bZP-)
    • @user17758193 你是对的。每个文档都有rels 字段吗?我使用$in 取得了成功。
    • 太棒了——做到了!非常感谢 - 我真的很感谢你在这里的帮助,特别是考虑到今天的日期......我为这个问题浪费了几天时间,你可能为我节省了更多的时间和挫败感。这似乎也是一个非常优雅和高性能的解决方案,非常好。再次感谢。
    • re:“是否每个文档都有一个 rels 字段” - 不保证,所以我保留了 $ifNull,ty
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-24
    相关资源
    最近更新 更多