【问题标题】:Join/lookup agregation on mongoose schema猫鼬模式中的加入/查找聚合
【发布时间】:2019-08-12 21:55:57
【问题描述】:

我目前正在制作一个成就系统并尝试将其保存在两个集合中。 一个包含名称和 ID 的集合, 以及与用户及其进度的其他集合。

我一直在研究 Aggregation 和 $lookup,并取得了一些进展,但我不确定需要做什么才能获得我想要的输出。

如果用户存在于成就中,则通过集合获取进度值及其用户ID,如果不存在,则将进度值设为0。

这会不会是某种加入,例如 Mysql?,这在 MongoDB 中会如何?

变量userid = 33;

尝试:

db.getCollection('achievements').aggregate([
   {
     $lookup:
       {
         from: "achievement_users",
         localField: "id",
         foreignField: "id",
         as: "inventory_docs"
       }
  }
])

成就架构:

{
    "name" : "testing",
    "id" : 1,
    "max" : 12,
},

{
    "name" : "testing2",
    "id" : 2,
    "max" : 12,

}

成就用户:

{
    "userid" : 33,
    "id" : 1,
    progress: 1,
},
 {
        "userid" : 446,
        "id" : 1,
        progress: 1,
    }

期望的输出:

{
name: "testing",
id: 1,
userid: 33,
progress: 1,
    max : 12,

},
{
name: "testing2",
id: 2,
progress: 0,
    max : 12,

},

编辑:

我需要用户已完成和未完成的所有成就(未完成 = 进度 = 0)。

可能是用户没有完成的成就。我也希望它们列出来,但进度值为 0。

更新 2: 还需要它来给我结果,而在成就用户中没有与该特定用户 ID 匹配的情况。

【问题讨论】:

    标签: javascript mongodb mongoose aggregation-framework schema


    【解决方案1】:

    如果您想执行类似于LEFT JOIN 的操作,这里有一个解决方案:

    db.test.aggregate([{
        $lookup: {
            from: "user",
            localField: "id",
            foreignField: "id",
            as: "inventory_docs"
        }
    }, {
        $unwind: {path: "$inventory_docs", preserveNullAndEmptyArrays: true }
    }, {
        $addFields: {
            userid: "$inventory_docs.userid",
            progress: {$cond: {if: "$inventory_docs.progress", then: "$inventory_docs.progress", else: 0 }},
        }
    }, {
        $project: {
            inventory_docs: 0
        }
    }])
    

    $lookup 从加入的集合中创建一个数组

    $unwind将数组拆分为记录

    $addFields随意提取你想要的字段

    $cond 用 0 替换空的进度

    $project 进行最后的清理

    【讨论】:

    • 谢谢!我能得到只有用户 ID 匹配的所有结果吗?而不是所有人? :)
    • 为了使用,在管道开头添加$match {$match: {id: {$in: ['1', '2']}}}
    • 所以只从用户行获取 userid = 33 的结果,只会显示该用户的成就(完成和未完成 ofc)。
    • 因为我不知道当我只有来自用户集合的用户 ID 时匹配会如何。
    • 还有@Julien,我可以从用户集合中反转它,这样它就可以了,获得成就,但它不会获得我所做的成就。有什么好主意可以解决吗? :)
    【解决方案2】:

    你可以使用下面的聚合

    db.achievement_users.aggregate([
      { "$match": { "userid": 33 }},
      { "$lookup": {
        "from": "achievement",
        "let": { "id": "$id", "progress": "$progress", "userid": "$userid" },
        "pipeline": [
          { "$addFields": {
            "progress": { "$cond": [{ "$eq": ["$id", "$$id"] }, "$$progress", 0] },
            "userid": "$$userid"
          }}
        ],
        "as": "inventory_docs"
      }},
      { "$unwind": "$inventory_docs" },
      { "$replaceRoot": { "newRoot": "$inventory_docs" }}
    ])
    

    【讨论】:

    • 但是useid只存储在用户成就列表中,而不是成就本身。我可以反过来做,但我不会得到用户没有的成就:/
    • 我已经从user_acheivement集合开始聚合。看看答案
    • 谢谢@Anthony,有没有办法缩短时间? (在 5k 用户行和 50 个成就上花费了 1.5 秒)。
    • 还有@anthony,如果用户没有成就,我需要成就(进度值为0)。所以我需要它已经完成的一切,而不是完成(任何行)。
    • 希望我对该问题的评论对您有所帮助
    猜你喜欢
    • 2021-10-24
    • 1970-01-01
    • 1970-01-01
    • 2019-07-20
    • 2021-05-06
    • 2020-12-01
    • 2015-05-19
    • 2018-02-05
    • 2021-07-22
    相关资源
    最近更新 更多