单链查询 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 获取所有评论的主要内容,如果未能解决你的问题,请参考以下文章

基于多个子文档的MongoDB/Mongoose查询

MongoDB(Mongoose)数据库查询问题

从两个数据库集合(Mongoose/MongoDB)中查询和匹配

Mongoose/mongoDB 查询加入.. 但我来自 sql 背景

Mongoose/mongoDB 查询加入.. 但我来自 sql 背景

查询 MongoDB 以返回 5 个最近的记录(Mongoose 框架)[重复]