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

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

所以我有四个收藏:

  1. 用户
{ "_id" : "2", "name" : "john" }
{ "_id" : "1", "name" : "Doe" }
  1. 帖子
{"_id": "2","body": "hello", likes: []},
{"_id": "1","name": "hello 4", likes: [1,]},
  1. 评论
{"_id": "c2","body": "hello 3",postId: "1",likes: [1,2]},
{"_id": "c1","body": "hello 2",postId: "1",likes: [1,2]},
  1. 回复
{"_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"]} 来检查用户是否喜欢该帖子、评论或回复

【问题讨论】:

标签: javascript php reactjs mongodb mongoose


【解决方案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"
      }
    }
  }
])

变更摘要

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

https://mongoplayground.net/p/lymCfeIIy9j

【讨论】:

  • 您可能必须在后端代码中处理此问题。因为replies 是一个数组,所以每种编程语言都可以默认返回它的长度。您可能不必从 mongo 本身投射它
  • 或者你可能需要在展开阶段使用`preserveNullAndEmptyArrays: true`来使用左连接而不是内连接
  • 例子:在两个小组赛阶段你需要添加createdAt : { $first:"$createdAt" }
  • 谢谢你,上帝保佑你,在你的生活和事业中。
  • 发送链接。我可以看看
猜你喜欢
  • 2016-07-01
  • 2017-12-15
  • 2021-08-04
  • 2019-03-20
  • 1970-01-01
  • 2018-12-29
  • 1970-01-01
  • 2016-07-01
  • 2020-11-29
相关资源
最近更新 更多