MongoDB 多表关联查询

情景

  • 目前有三个表: articles(文章) users(用户) comments(评论),表结构如下:
  1. articles
    title: String,// 文章标题
    content: String,// 文章内容
    read: {    // 文章阅读量
      type: Number,
      default: 0,
    },
    star: {// 文章点赞量
      type: Number,
      default: 0,
    },
    comment: {// 文章评论量
      type: Number,
      default: 0,
    },
    authorId: String,// 文章作者
    
  2. users
    username: String,// 用户名
    avatar: String,// 头像
    gender: String,// 性别
    phone: String,// 手机号
    email: String,// 邮箱
    password: {    // 密码
      type: String,
      select: false,
    },
    
  3. comments
    content: String,// 评论的内容
    articleId: String,// 文章id,外键
    authorId: String,// 文章作者,外键
    userId: String,// 当前用户
    

实现多表关联,查询comments表时,将对应的文章作者(通过authorId在users表里找到)和文章详情(通过articleId在articles表里找到)一起返回

  • 第一种方式 使用 aggregate 管道聚合查询

    // 查询评论详情
    const findComment = async (ctx) => {
      const { id } = ctx.params;
      const comment= await Comment.aggregate([
        {
          $lookup: {
            from: "articles", // 关联 articles 表
            localField: "articleId", // 根据 comments 里 articleId 字段查询
            foreignField: "_id", // 查找 articles 表里对应的 _id 的数据
            as: "articles",// 返回的字段别名
          },
        },
        {
          $lookup: {
            from: "users", // 关联 users 表
            localField: "authorId", // 根据 comments里 authorId 字段查询
            foreignField: "_id", // 查找 users 表里对应的 _id 的数据
            as: "author",// 返回的字段别名
          },
        },
        // 创建一个 mongoDB 的 ObjectId: mongoose.Types.ObjectId
        { $match: { _id: mongoose.Types.ObjectId(id) } },
      ]);
    }
    
  • 第二种方式 使用 populate 关联查询

    1. 定义 Comment 模型,在定义模型时,需要使用 ref 来引用要关联的模型

      const mongoose = require("mongoose");
      const schame = new mongoose.Schema({
        content: String,// 评论的内容
        articleId: {
          type: mongoose.Schema.Types.ObjectId,
          ref: "Article",  // 文章模型的名称
        },// 文章id,外键
        authorId: {
          type: mongoose.Schema.Types.ObjectId,
          ref: "User",  // 用户模型的名称
        },// 文章作者,外键
        userId: String,// 当前用户
      })
      const Comment = mongoose.model("Comment", schame, "comments");
      module.exports = Comment;
      
    2. 使用 populate查询,引入所有关联的模型

      const Comment = require("../models/comment");
      const Article = require("../models/article");
      const User = require("../models/user");
      // 查询评论详情
      const findComment = async (ctx) => {
        const { id } = ctx.params;
        const comment= await Comment.findOne({ _id: id }).populate("articleId").populate("authorId").lean()
        ctx.body = {
          comment
        }
      }
      

总结

  • MongoDB 经常用到的就是这两种方式,populate 方式需要 MongoDB 版本号 > 3.2
  • 推荐使用 aggregate 方式

参考文献:

上一篇:从MongoDB迁移到TDengine后,成本显著下降


下一篇:jmeter连接MongoDB数据库,并且将查询的数据作为下一个接口的请求参数