mongoose中聚合——aggregate的使用

aggregate()

\color{red}{语法}

db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION);

\color{red}{数据}

数据使用菜鸟教程的数据啦🤪🤪

/* 1 */
{
    "_id" : ObjectId("5e86e29788e64443e448dfc0"),
    "title" : "MongoDB Overview",
    "description" : "MongoDB is no sql database",
    "by_user" : "runoob.com",
    "url" : "http://www.runoob.com",
    "tags" : [ 
        "mongodb", 
        "database", 
        "NoSQL"
    ],
    "likes" : 100
}

/* 2 */
{
    "_id" : ObjectId("5e86e2ad88e64443e448dfd2"),
    "title" : "NoSQL Overview",
    "description" : "No sql database is very fast",
    "by_user" : "runoob.com",
    "url" : "http://www.runoob.com",
    "tags" : [ 
        "mongodb", 
        "database", 
        "NoSQL"
    ],
    "likes" : 10
}

/* 3 */
{
    "_id" : ObjectId("5e86e2bc88e64443e448dfd7"),
    "title" : "Neo4j Overview",
    "description" : "Neo4j is no sql database",
    "by_user" : "Neo4j",
    "url" : "http://www.neo4j.com",
    "tags" : [ 
        "neo4j", 
        "database", 
        "NoSQL"
    ],
    "likes" : 750
}

\color{red}{管道操作符}

操作符 含义
$group 将collection中的document分组,可用于统计结果
$match 过滤数据,只输出符合结果的文档
$project 修改输入文档的结构(例如重命名,增加、删除字段,创建结算结果等)
$sort 将结果进行排序后输出
$limit 限制管道输出的结果个数
$skip 跳过制定数量的结果,并且返回剩下的结果
$unwind 将数组类型的字段进行拆分

\color{red}{表达式操作符}

操作符 含义 实例
$sum 计算总和,{$sum: 1}表示返回总和×1的值(即总和的数量),使用{$sum: '$制定字段'}也能直接获取制定字段的值的总和 db.collection.aggregate([{$group : {_id : "$by_user", content_sum : {$sum : "$likes"}}}])
$avg 平均值 db.collection.aggregate([{$group : {_id : "$by_user", content_sum : {$avg : "$likes"}}}])
$min 获取集合中所有文档对应值得最小值 db.collection.aggregate([{$group : {_id : "$by_user", content_sum : {$min : "$likes"}}}])
$max 获取集合中所有文档对应值得最大值 db.collection.aggregate([{$group : {_id : "$by_user", content_sum : {$max : "$likes"}}}])
$push 在结果文档中插入值到一个数组中 db.collection.aggregate([{$group : {_id : "$by_user", url : {$push : "$url"}}}])
$addToSet 在结果文档中插入值到一个数组中,但不创建副本 db.collection.aggregate([{$group : {_id : "$by_user", url : {$addToSet : "$url"}}}])
$first 根据资源文档的排序获取第一个文档数据 db.collection.aggregate([{$group : {_id : "$by_user", url : {$first : "$url"}}}])
$last 根据资源文档的排序获取最后一个文档数据 db.collection.aggregate([{$group : {_id : "$by_user", url : {$last : "$url"}}}])

\color{skyblue}{具体例子}

  • $group

    • 简单阐述

      //将document分组,用作统计结果
      db.collection.aggregate([       // aggregate方法接收的是一个数组
          {
              $group: {
              	// _id字段表示要基于哪个字段来进行分组(即制定字段值相同的为一组)
              	// $by_user表示要基于$by_user字段来进行分组
                  _id: '$by_user', 
                  // content_sum字段的值$sum: 1表示的是获取满足by_user字段相同的这一组的数量乘以后面给定的值(本例为1,那么就是同组的数量)。
                  content_sum: {$sum: 1}
              }
          }
      ])
      
    • 具体案例

      通过以上集合计算每个作者所写的文章数(通过字段by_user 字段对数据进行分组,并计算by_user字段相同值的总和),使用aggregate()计算结果如下:

      router.get('/getInfo',async(req, res)=>{
      let data=await Content.aggregate([
        {
          $group:{
            _id:'$by_user',
            content_sum:{$sum:1}
          }
        }
      ])
      res.json({data})
      })
      

      在这里插入图片描述

  • $match

    获取likes的值在50-200之间的数据:

    router.get('/getInfo', async (req, res) => {
      let data = await Content.aggregate([{
          $match: {
            likes: {
              $gt: 50,
              $lte: 200
            }
          }
        },
        {
          $group: {
            _id: '$_id',
            content_sum: {
              $sum: 1
            }
          }
        }
      ])
      res.json({
        data
      })
    })
    

    在这里插入图片描述

    从图中可以看出likes的值在50-200之间的数据只有1条,现在我们只知道这条数据的_id,如果想知道这条数据的具体信息时应该如何操作呢❓上面的表格中提到$project修改输入文档的结构(例如重命名,增加、删除字段,创建结算结果等),所以一起来看看吧👇👇👇

  • $project

    router.get('/getInfo', async (req, res) => {
      let data = await Content.aggregate([
        {
          $match: { likes: { $gt: 50, $lte: 200 } }
        },
        {
        //以下的值可以写$+字段,也可以使用0 和1来表示,若要显示字段则为1,否则为0
         
         //$project:{_id:'$_id',title:"$title",description:"$description",by_user:"$by_user",url:'$ulr',tags:'$tags',likes:'$likes'}
         $project:{_id:1,title:1,description:1,by_user:1,url:1,tags:1,likes:1}
        }
      ])
      res.json({
        data
      })
    })
    

    在这里插入图片描述

  • 以上3个操作符的综合使用

    如果想拿到所有likes>=10的document的by_user字段可以把管道搭配起来用:

    router.get('/getInfo', async (req, res) => {
      let data = await Content.aggregate([{
          $match: {
            likes: {
              $gt: 10
            }
          }
        },
        // 注意$project与$group的顺序,换位置后数据为空
        {
          $project: {
            _id: 0, //_id不显示
            by_user: 1 //by_user显示
          }
        },
        {
          $group: {
            _id: null,
            gameName: {
              $push: '$by_user'
            }
          }
        }
      ])
      res.json({
        data
      })
    })
    

    在这里插入图片描述

  • $sort

    • 根据likes进行降序排序

      router.get('/getInfo', async (req, res) => {
        let data = await Content.aggregate([
          {
            $project: { _id: 1, by_user: 1, title: 1, title: 1, description: 1, url: 1, tags: 1, likes: 1 }
          },
          {
            $sort: { likes: -1 }
          },
        ])
        res.json({
          data
        })
      })
      

      在这里插入图片描述

    • 根据likes进行升序排序

      router.get('/getInfo', async (req, res) => {
        let data = await Content.aggregate([
          {
            $project: { _id: 1, by_user: 1, title: 1, title: 1, description: 1, url: 1, tags: 1, likes: 1 }
          },
          {
            $sort: { likes: 1 }
          },
        ])
        res.json({
          data
        })
      })
      

      在这里插入图片描述

  • $limit and $skip

    router.get('/getInfo', async (req, res) => {
      let data = await Content.aggregate([
        {
          $project: { _id: 1, by_user: 1, title: 1, title: 1, description: 1, url: 1, tags: 1, likes: 1 }
        },
        {
          $sort: { likes: 1 }
        },
        {
          $skip:1
        },
        {
          $limit:1
        }
      ]);
      
      res.json({
        data
      })
    })
    

    在这里插入图片描述

  • $unwind

    $unwind管道以document中的数组类型的字段进行拆分,每条包含数组中的一个值。

    比如拆分likes:10这条数据,先来看看整体数据信息吧:

    {
        "_id" : ObjectId("5e86e2ad88e64443e448dfd2"),
        "title" : "NoSQL Overview",
        "description" : "No sql database is very fast",
        "by_user" : "runoob.com",
        "url" : "http://www.runoob.com",
        "tags" : [ 
            "mongodb", 
            "database", 
            "NoSQL"
        ],
        "likes" : 10
    }
    

    tags数组中有3条数据,所以拆分后会显示3条数据,看看具体实现吧:

    router.get('/getInfo', async (req, res) => {
      let data = await Content.aggregate([
        {
          $match: {
            likes: 10
          }
        },
        {
          $unwind:'$tags'
        },
        {
          $project: { _id: 1, by_user: 1, title: 1, title: 1, description: 1, url: 1, tags: 1, likes: 1 }
        },
      ])
      res.json({
        data
      })
    })
    

    在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章