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
      })
    })
    

    在這裏插入圖片描述

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