具有 3 个级别的 MongoDB 嵌套查找并将新值附加到结果文档

Posted

技术标签:

【中文标题】具有 3 个级别的 MongoDB 嵌套查找并将新值附加到结果文档【英文标题】:MongoDB nested lookup with 3 levels and append new value to the result docs 【发布时间】:2021-08-06 09:30:00 【问题描述】:

我需要从数据库中检索整个单个对象层次结构作为 JSON。实际上,关于实现此结果的任何其他解决方案的建议将受到高度评价。我决定使用具有 $lookup 支持的 MongoDB。

所以我有四个收藏:

    用户
 "_id" : "2", "name" : "john" 
 "_id" : "1", "name" : "Doe" 
    帖子
"_id": "2","body": "hello", likes: [],
"_id": "1","name": "hello 4", likes: [1,],
    评论
"_id": "c2","body": "hello 3",postId: "1",likes: [1,2],
"_id": "c1","body": "hello 2",postId: "1",likes: [1,2],
    回复
"_id": "r1","name": "hello 4",commentId: "c1",likes: [1],
"_id": "r3","name": "hello five",commentId: "c2",likes: [1,2]

我基本上需要检索所有带有所有相应 cmets 和 cmets.replies 的帖子作为我的结果的一部分。我的聚合:

  const posts = await PostModel.aggregate([
      
        $lookup: 
          from: "comments",
          localField: "_id",
          foreignField: "postId",
          as: "comments",
        ,
      ,
      
        $unwind: "$comments",
      ,
      
        $lookup: 
          from: "replies",
          localField: "comments._id",
          foreignField: "commentId",
          as: "comments.replies",
        ,
      ,
    ]).sort(
      createdAt: -1,
    );

MongoDb PlayGround

结果很奇怪。有些记录没问题。但是 cmets 返回一个对象。 _id="1" 的帖子也有一些重复。

[
  
    "_id": "1",
    "comments": 
      "_id": "c2",
      "body": "hello 3",
      "likes": [
        1,
        2
      ],
      "postId": "1",
      "replies": [
        
          "_id": "r3",
          "commentId": "c2",
          "likes": [
            1,
            2
          ],
          "name": "hello five"
        
      ]
    ,
    "likes": [
      1
    ],
    "name": "hello 4"
  ,
  
    "_id": "1",
    "comments": 
      "_id": "c1",
      "body": "hello 2",
      "likes": [
        1,
        2
      ],
      "postId": "1",
      "replies": [
        
          "_id": "r1",
          "commentId": "c1",
          "likes": [
            1
          ],
          "name": "hello 4"
        
      ]
    ,
    "likes": [
      1
    ],
    "name": "hello 4"
  
]

简而言之,这是我的预期结果。

我想获取所有帖子,以及与之关联的所有 cmets 和回复。 我想添加一个喜欢的计数likesCount:$size:["likes"],因为我已经准备好用户身份验证 ID(uid),我想根据isLiked: $in:[ID(uid),"likes"] 来检查用户是否喜欢该帖子、评论或回复

【问题讨论】:

您可能必须将其与帖子 ID mongoplayground.net/p/MaGfTdTS6v0 组合在一起 每条评论的回复数? @Beingnin ama 将如何访问replies.likes 并统计它们 @Beingnin (mongoplayground.net/p/MaGfTdTS6v0)[mongoplayground.net/p/MaGfTdTS6v0] 【参考方案1】:

由于每个帖子都有多个 cmets,展开 cmets 后需要将它们组合在一起形成一个数组

更新 我已经更新了 fetch 方法,如下所示。

  db.posts.aggregate([
  
    $lookup: 
      from: "comments",
      localField: "_id",
      foreignField: "postId",
      as: "comments",
      
    ,
    
  ,
  
    $unwind: "$comments",
    
  ,
  
    $lookup: 
      from: "replies",
      localField: "comments._id",
      foreignField: "commentId",
      as: "replies",
      
    ,
    
  ,
  
    $unwind: "$replies",
    
  ,
  
    "$addFields": 
      "replies.countOflikes": 
        $size: 
          $ifNull: [
            "$replies.likes",
            []
          ]
        
      ,
      "replies.isLiked": 
        $cond: 
          if: 
            $eq: [
              
                $size: 
                  $filter: 
                    input: "$replies.likes",
                    as: "item",
                    cond: 
                      $eq: [
                        "$$item",
                        1//id of the user whom you wanna check if liked the reply
                        
                      ]
                    
                  
                
              ,
              0
            ]
          ,
          then: false,
          else: true
        
      
    
  ,
  
    $group: 
      _id: "$comments._id",
      postId: 
        $first: "$_id"
      ,
      body: 
        $first: "$body"
      ,
      "comments": 
        $first: "$comments"
      ,
      replies: 
        $push: "$replies"
      
    
  ,
  
    $addFields: 
      "comments.replies": "$replies"
    
  ,
  
    $group: 
      _id: "$postId",
      body: 
        $first: "$body"
      ,
      comments: 
        $push: "$comments"
      
    
  
])

变更摘要

    展开两个 cmets 及其回复 添加了用于显示 isLikedcountOfLikes 的新字段,使用 addFields 舞台 两次分组以改造数据的原始结构(先按 cmets 分组,然后按帖子分组

https://mongoplayground.net/p/lymCfeIIy9j

【讨论】:

您可能必须在后端代码中处理此问题。因为replies 是一个数组,所以每种编程语言都可以默认返回它的长度。您可能不必从 mongo 本身投射它 或者你可能需要在展开阶段使用`preserveNullAndEmptyArrays: true`来使用左连接而不是内连接 例子:在两个小组赛阶段你需要添加createdAt : $first:"$createdAt" 谢谢你,上帝保佑你,在你的生活和事业中。 发送链接。我可以看看

以上是关于具有 3 个级别的 MongoDB 嵌套查找并将新值附加到结果文档的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB查询:如何查找嵌套对象中的字符串

MongoDB - 仅当嵌套数组中的所有条目存在时才更新它们

使用 sum 的 MongoDB 嵌套查找

mongodb $查找带有投影的数组中的嵌套对象

从 mongoDB 迁移到 clickhouse 中的嵌套数据结构

使用 Itertools 具有内部中断的可变级别的嵌套循环