单链查询 mongodb / mongoose 获取所有评论
Posted
技术标签:
【中文标题】单链查询 mongodb / mongoose 获取所有评论【英文标题】:single chained query mongodb / mongoose to fetch all comments 【发布时间】:2021-02-01 00:47:24 【问题描述】:我正在尝试开发一个个人项目,一个以类似于 Stack Exchange 的方式运行的网站,用户可以提出一个可以收到多个答案的问题。每个问题和答案可以有多个 cmets。
我正在使用 nodeJS 作为我的后端。
如何在单个 mongoDB / mongoose 查询中为 all 获取特定问题的答案的 all cmets?
如果您能告诉我如何获取 所有 特定问题的答案以及 所有单个 mongoDB / mongoose 查询中问题的 cmets?
Mongoose 架构:
const questionSchema = new mongoose.Schema(
title: String,
content: String
)
const answerSchema = new mongoose.Schema(
questionId: String,
content: String,
)
const commentSchema = new mongoose.Schema(
idQuestion: String, // nullable
idAnswer: String, // nullable
content: String
)
目前,我正在执行猫鼬查询以查找特定问题的所有答案。然后,使用forEach
,对每个答案执行猫鼬查询,以找到每个答案的所有 cmets。我认为这是非常费力的,性能方面的,并不是实现我想要实现的目标的理想方式。
【问题讨论】:
您似乎将您的 Mongo 实例视为关系数据库,您是否考虑过在问题中嵌入答案,以及在答案中嵌入评论(假设他们会去的地方)? @Nimnam1 我虽然有这样做,但我想知道我的设置方式是否可行? 看看***.com/questions/36019713/…,如果这不能回答你的问题,我可以看看我是否能提出一些建议。 你在错误地使用 Mongo,你应该对你的数据进行非规范化。 【参考方案1】:您可以尝试以下聚合。匹配问题 ID,然后加入以查找所有带有问题 ID 的答案 ID,然后查找以提取所有 cmets。
db.questions.aggregate([
"$match":"_id":input_question_id,
"$lookup":
"from":"answers",
"localField":"_id",
"foreignField":"questionId",
"as":"answers"
,
"$lookup":
"from":"comments",
"let":"ids":"answers_id":"$answers._id","question_id":"$_id",
"pipeline":[
"$match":"$expr":
"$or":[
"$eq":["$idQuestion","$$ids.question_id"],
"$in":["$idAnswer","$$ids.answers_id"]
]
],
"as":"comments"
,
"$project":"comments":"$comments.content"
])
这里的工作示例 - https://mongoplayground.net/p/qBlKqk-JsxA
【讨论】:
【参考方案2】:你可以试试,
$match
你的条件questionId
$lookup 加入comments
db.answers.aggregate([
$match: questionId: 1 ,
$lookup:
from: "comments",
localField: "_id",
foreignField: "idAnswer",
as: "comments"
])
Playground
第二种方法,如果您想选择带有所有答案和评论的问题然后尝试,
$match
你的条件
$lookup with pipeline 加入answers
收藏
管道字段可以允许添加我们在根级别使用的管道的所有阶段
$match
questionId 并获得答案
$lookup
加入cmets收藏
db.questions.aggregate([
$match: _id: 1 , // this is optional if you want to select all questions then remove this
$lookup:
from: "answers",
let: questionId: "$_id" ,
pipeline: [
$match: $expr: $eq: ["$$questionId", "$questionId"] ,
$lookup:
from: "comments",
localField: "_id",
foreignField: "idAnswer",
as: "comments"
],
as: "answers"
])
Playground
显示或隐藏额外字段,您可以在上述查询末尾使用$project 运算符,
您可以根据需要显示字段
$project:
_id: 1,
content: 1,
"comments._id": 1,
"comments.content": 1
Playground
建议:
我不确定,您是否已经完成,但尝试在引用字段中定义对象 ID 类型而不是字符串类型,就像我更新了您的架构一样,这将在对象 ID 中添加一个默认索引,这将增加获取数据的速度,
const answerSchema = new mongoose.Schema(
questionId: mongoose.Types.ObjectId,
content: String,
)
const commentSchema = new mongoose.Schema(
idQuestion: mongoose.Types.ObjectId, // nullable
idAnswer: mongoose.Types.ObjectId, // nullable
content: String
)
【讨论】:
非常感谢!您能多解释一下管道是什么吗?我不是mongodb的专家,也不是很懂是什么?它是否从以前的$lookup
获取结果并“通过管道”将其推入另一个操作?
这是一个聚合查询,在内部我们使用了带有特定运算符的单独对象,称为管道阶段,$lookup
是一个管道运算符,用于加入特定集合并在数组字段中返回匹配数据,有有两种查找,一种是我们在第一次查询中使用的简单查找,第二种是使用管道查找,我们可以使用管道字段并在该管道字段中添加任何管道阶段。
我认为 op 想要从问题和所有答案中获取 cmets。您可以在一个查询中完成,如我的答案所示。
@svr 我不确定,他没有提到,根据我的理解,我提供了 2 个选项,实际上他在第一条评论中看起来很满意。我认为他不清楚期望,也是聚合查询的新手。
@turivishal 你能在第二种方法中获取问题的 cmets 吗?以上是关于单链查询 mongodb / mongoose 获取所有评论的主要内容,如果未能解决你的问题,请参考以下文章
从两个数据库集合(Mongoose/MongoDB)中查询和匹配
Mongoose/mongoDB 查询加入.. 但我来自 sql 背景