具有 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 及其回复
添加了用于显示
isLiked
和 countOfLikes
的新字段,使用 addFields
舞台
两次分组以改造数据的原始结构(先按 cmets 分组,然后按帖子分组)
https://mongoplayground.net/p/lymCfeIIy9j
【讨论】:
您可能必须在后端代码中处理此问题。因为replies
是一个数组,所以每种编程语言都可以默认返回它的长度。您可能不必从 mongo 本身投射它
或者你可能需要在展开阶段使用`preserveNullAndEmptyArrays: true`来使用左连接而不是内连接
例子:在两个小组赛阶段你需要添加createdAt : $first:"$createdAt"
谢谢你,上帝保佑你,在你的生活和事业中。
发送链接。我可以看看以上是关于具有 3 个级别的 MongoDB 嵌套查找并将新值附加到结果文档的主要内容,如果未能解决你的问题,请参考以下文章
MongoDB - 仅当嵌套数组中的所有条目存在时才更新它们