猫鼬模式中的加入/查找聚合

Posted

技术标签:

【中文标题】猫鼬模式中的加入/查找聚合【英文标题】: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 匹配的情况。

【问题讨论】:

【参考方案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)。所以我需要它已经完成的一切,而不是完成(任何行)。 希望我对该问题的评论对您有所帮助

以上是关于猫鼬模式中的加入/查找聚合的主要内容,如果未能解决你的问题,请参考以下文章

猫鼬聚合反向查找或没有localField的查找[重复]

为啥聚合+排序比mongo中的查找+排序更快?

通过嵌套数组查找猫鼬组

在猫鼬中,如何根据相关集合中的值查找记录?

猫鼬从模型中的数组中查找对象

从猫鼬聚合管道中的数组数组中获取单个数组