Mongodb之聚合查询语句aggregate()的灵活用法

802 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情

本文内容:
1.一条简单的聚合查询语句。
2.连表查询,用第一个表的条件,去查第二个表的数据。
3.一段查询语句查询三个表,递进查询。

前言

本文主要是介绍mongodb聚合查询语句的灵活用法,文章用到的是 mongodb + orm 的方式来操作数据库。

一条简单的聚合查询语句

假设有个作品表 artworkRepo,前端传了一个作品ID artworkId 进来查某个作品信息,我们可以这样做

import { ObjectID } from "mongodb";

async function getArtworkByArtworkId(artworkId: string) {
   const res = await artworkRepo.aggregate([
       { $match: { _id: { $eq: new ObjectID(artworkId) } } }, 
    ]).toArray();
}

其中 $match 操作符,是条件操作符,就是放查询条件的地方,相当于一个过滤器。$eq 操作符对比两个数是否相等。这里也可以写成 _id: new ObjectID(artworkId)。我这里的_id在数据库中的类型是objectId,而前端传过来的是 string 类型,所以需要转一下类型,在使用过程中要按实际情况来使用。

连表查询

接下来我们就开始连表查询的语句。
假设作品表中有一个作者ID authorId ,我现在要在查询作品的同时把作者的信息查询出来,我应该怎么做呢?一个方法是,先用一条查询语句查出作品的信息,从返回的结果中取出 authorId,再写一条语句,根据 authorId 去查作者信息。第二个方法就是,用连表查询来查,两种方法都可以,看你怎么用,我们来看第二种方法怎么实现。

import { ObjectID } from "mongodb";

async function getArtworkByArtworkId(artworkId: string) {
   const res = await artworkRepo.aggregate([
       { 
          $match: { _id: { $eq: new ObjectID(artworkId) } } 
       },
       // $addFields操作符 相当与定义了一个变量,$authorId 是 作品表里的 authorId
       { $addFields: { _authorId: "$authorId" } }, 
       {
         $lookup: {
           from: "users", // 用户表
           localField: "_authorId", // $addFields 中定义的变量
           foreignField: "_id", // 这个是 users 表中的 _id
           as: "author", // 起一个别名
         },
       },
    ]).toArray();
}

返回的数据大概是这样的:

res = [
    {
        _id: testtest...,
        authorId: testtest...,
        author: [...]
    }
]

那如果我查第二个表的时候,也需要根据几个条件来查呢,这时又该怎么做呢?
$lookup 有没有其他的写法呢?答案是有的,接下来就来实现一下。
刚才是根据作品表查作者,那现在反过来。

import { ObjectID } from "mongodb";

async function getUserArtwork(userId: string) {
   const res = await userRepo.aggregate([
       { 
          $match: { _id: { $eq: new ObjectID(userId) } } 
       },
       {
         $lookup: {
           from: "artworks", // 作品表
           let: { userId: "$_id" }, // 定义一个变量 ( users表中的_id )
           pipeline: [
            {
              $match: {
                $expr: {
                  $eq: ["$authorId", "$$userId"], // authorId == userId
                },
                isShow: true
              },
            },
          ],
          as: "artworks", // 起一个别名
         },
       },
    ]).toArray();
}

现在第二个表也有条件限制啦,这里主要理解 pipeline 的用法。

一段查询语句查询三个表,递进查询

作品中有其对应中评论内容,作品的评论在评论表中,怎么查呢,一个方法就是分开查询啦,第二个方法就是在同一段语句中写查询语句,接下来就着手实现吧!

观察上面 pipeline 中的代码,可以发现,其中的结构,和上一层的结构几乎一样,所以mongodb让我们可以在 pipeline 继续使用 $lookup

import { ObjectID } from "mongodb";

async function getUserArtwork(userId: string) {
   const res = await userRepo.aggregate([
       { 
          $match: { _id: { $eq: new ObjectID(userId) } } 
       },
       {
         $lookup: {
           from: "artworks", // 作品表
           let: { userId: "$_id" }, // 定义一个变量 ( users表中的_id )
           pipeline: [
           {
              $addFields: {
                _artworkId: "$_id", // 作品表中的作品ID
              },
            },
            {
              $match: {
                $expr: {
                  $eq: ["$authorId", "$$userId"], // authorId == userId
                },
                isShow: true
              },
            },
            // 这里是第三个表啦
            {
              $lookup: {
                from: "artwork_comment",
                localField: "_artworkId", // 作品表中的作品ID
                foreignField: "artworkId",
                as: "comments",
              },
            },
          ],
          as: "artworks", // 起一个别名
         },
       },
    ]).toArray();
}

写在最后

至此,文章就分享完毕了,欢迎在评论区交流。
如果文章对你有所帮助,不要忘了点上宝贵的一赞!
听说点赞的人运气都不差,相信来年第一个升职加薪的一定是你~