天天看點

MongoDB 進階查詢 aggregate 聚合管道

1. MongoDB 聚合管道簡介

使用聚合管道可以對集合中的文檔進行變換群組合,常用于多表關聯查詢、資料的統計。

db.COLLECTION_NAME.aggregate() 方法用來建構和使用聚合管道,下圖是官網給的執行個體,可以看出來聚合管道的用法還是比較簡單的。

MongoDB 進階查詢 aggregate 聚合管道

2. MongoDB Aggregation 管道操作符與表達式

常用的管道操作符有以下這些:

MongoDB 進階查詢 aggregate 聚合管道

MySQL 和 MongoDB 的聚合 對比 :

MongoDB 進階查詢 aggregate 聚合管道

管道操作符作為 “ 鍵 ”, 所對應的“ 值 ”叫做管道表達式, 如 {$match:{status:"A"}} , $match 稱為管道操作符,而 status:"A"稱為管道表達式,每個管道表達式是一個文檔結構,它是由字段名、字段值、和一些表達式操作符組成的,常用的表達式操作符有以下這些。

MongoDB 進階查詢 aggregate 聚合管道

3. 模拟資料

為了說明每個管道操作符的作用,将以下面資料為參考,分别有order和order_item兩個集合。

order集合裡的資料

{
    "_id": ObjectId("5e6f15c1eb57cc45bde8130b"),
    "order_id": "1",
    "uid": 10,
    "trade_no": "111",
    "all_price": 100,
    "all_num": 2
}
{
    "_id": ObjectId("5e6f15cbeb57cc45bde8130c"),
    "order_id": "2",
    "uid": 7,
    "trade_no": "222",
    "all_price": 90,
    "all_num": 2
}
{
    "_id": ObjectId("5e6f15d4eb57cc45bde8130d"),
    "order_id": "3",
    "uid": 9,
    "trade_no": "333",
    "all_price": 20,
    "all_num": 6
}           

複制

order_item集合裡的資料

{
    "_id": ObjectId("5e6f15dbeb57cc45bde8130e"),
    "order_id": "1",
    "title": "商品滑鼠 1",
    "price": 50,
    "num": 1
}
{
    "_id": ObjectId("5e6f15e2eb57cc45bde8130f"),
    "order_id": "1",
    "title": "商品鍵盤 2",
    "price": 50,
    "num": 1
}
{
    "_id": ObjectId("5e6f15e8eb57cc45bde81310"),
    "order_id": "1",
    "title": "商品鍵盤 3",
    "price": 0,
    "num": 1
}
{
    "_id": ObjectId("5e6f15f1eb57cc45bde81311"),
    "order_id": "2",
    "title": "牛奶",
    "price": 50,
    "num": 1
}
{
    "_id": ObjectId("5e6f15faeb57cc45bde81312"),
    "order_id": "2",
    "title": "酸奶",
    "price": 40,
    "num": 1
}
{
    "_id": ObjectId("5e6f1603eb57cc45bde81313"),
    "order_id": "3",
    "title": "礦泉水",
    "price": 2,
    "num": 5
}
{
    "_id": ObjectId("5e6f160aeb57cc45bde81314"),
    "order_id": "3",
    "title": "毛巾",
    "price": 10,
    "num": 1
}           

複制

4. 管道操作符 $project

修改文檔的結構,可以用來重命名、增加或删除文檔中的字段。

例:要求查找 order 集合, 隻傳回文檔中 trade_no 和 all_price 字段。

db.order.aggregate([
    {
        $project:{ trade_no:1, all_price:1 }
    }
])           

複制

執行結果:

{ "_id" : ObjectId("5e6f15c1eb57cc45bde8130b"), "trade_no" : "111", "all_price" : 100 }

{ "_id" : ObjectId("5e6f15cbeb57cc45bde8130c"), "trade_no" : "222", "all_price" : 90 }

{ "_id" : ObjectId("5e6f15d4eb57cc45bde8130d"), "trade_no" : "333", "all_price" : 20 }           

複制

5. 管道操作符 $match

用于過濾文檔,用法類似于 find() 方法中的參數。

例:要求查找 order 集合,隻傳回文檔中 trade_no 和 all_price 字段,并隻顯示 all_price 大于等于90的記錄。

db.order.aggregate([
    { 
        $project: { trade_no: 1, all_price: 1}
    },
    { 
        $match: {
            "all_price": {$gte: 90}
        }
    }
])           

複制

執行結果:

{ "_id" : ObjectId("5e6f15c1eb57cc45bde8130b"), "trade_no" : "111", "all_price" : 100 }

{ "_id" : ObjectId("5e6f15cbeb57cc45bde8130c"), "trade_no" : "222", "all_price" : 90 }           

複制

6. 管道操作符 $group

将集合中的文檔進行分組,可用于統計結果。

例:統計每個訂單的訂單數量,按照訂單号分組。

db.order_item.aggregate([
    {   
        $group: 
            {_id: "$order_id", total: {$sum: "$num"}
        }
    }
])           

複制

執行結果:

{ "_id" : "2", "total" : 2 }

{ "_id" : "3", "total" : 6 }

{ "_id" : "1", "total" : 3 }           

複制

7. 管道操作符 $sort

将集合中的文檔進行排序。

例:要求查找 order 集合, 隻傳回文檔中 trade_no 和 all_price 字段,隻顯示 all_price 大于等于90的記錄,并以all_price進行降序排列。

db.order.aggregate([
    { 
        $project: { trade_no: 1, all_price: 1}
    },
    { 
        $match: {
            "all_price": {$gte: 90}
        }
    },
    { 
        $sort: {"all_price": -1}
    }
])           

複制

執行結果:

{ "_id" : ObjectId("5e6f15c1eb57cc45bde8130b"), "trade_no" : "111", "all_price" : 100 }

{ "_id" : ObjectId("5e6f15cbeb57cc45bde8130c"), "trade_no" : "222", "all_price" : 90 }           

複制

8. 管道操作符 $limit

限制查詢結果的數量。

例:要求查找 order 集合,隻傳回文檔中 trade_no 和 all_price 字段,隻顯示 all_price 大于等于90的記錄,以all_price進行降序排列,并隻顯示1條記錄。

db.order.aggregate([
    { 
        $project: { trade_no: 1, all_price: 1}
    },
    { 
        $match: {
            "all_price": {$gte: 90}
        }
    },
    { 
        $sort: {"all_price": -1}
    },
    { 
        $limit: 1
    }
])           

複制

執行結果:

{ "_id" : ObjectId("5e6f15c1eb57cc45bde8130b"), "trade_no" : "111", "all_price" : 100 }           

複制

9. 管道操作符 $skip

對查詢結果跳過幾條記錄進行顯示。

例:要求查找 order 集合,隻傳回文檔中 trade_no 和 all_price 字段,隻顯示 all_price 大于等于90的記錄,以 all_price 進行降序排列,并跳過1條記錄顯示其結果。

db.order.aggregate([
    { 
        $project: { trade_no: 1, all_price: 1}
    },
    { 
        $match: {
            "all_price": {$gte: 90}
        }
    },
    { 
        $sort: {"all_price": -1}
    },
    { 
        $skip: 1
    }
])           

複制

執行結果:

{ "_id" : ObjectId("5e6f15cbeb57cc45bde8130c"), "trade_no" : "222", "all_price" : 90 }           

複制

10. 管道操作符 $lookup

對要查詢的結果時行多表關聯查詢。

例:查詢 order 集合,關聯到order_item集合,将 order 中 order_id 與 order_item 中order_id 相同的記錄顯示出來,并将結果取名為 items。

db.order.aggregate([
    { 
        $lookup: { 
            from: "order_item", 
            localField: "order_id", 
            foreignField: "order_id", 
            as: "items"
        }
    }
])           

複制

執行結果:

{
    "_id": ObjectId("5e6f15c1eb57cc45bde8130b"),
    "order_id": "1",
    "uid": 10,
    "trade_no": "111",
    "all_price": 100,
    "all_num": 2,
    "items": [
        {
            "_id": ObjectId("5e6f15dbeb57cc45bde8130e"),
            "order_id": "1",
            "title": "商品滑鼠 1",
            "price": 50,
            "num": 1
        },
        {
            "_id": ObjectId("5e6f15e2eb57cc45bde8130f"),
            "order_id": "1",
            "title": "商品鍵盤 2",
            "price": 50,
            "num": 1
        },
        {
            "_id": ObjectId("5e6f15e8eb57cc45bde81310"),
            "order_id": "1",
            "title": "商品鍵盤 3",
            "price": 0,
            "num": 1
        }
    ]
}
{
    "_id": ObjectId("5e6f15cbeb57cc45bde8130c"),
    "order_id": "2",
    "uid": 7,
    "trade_no": "222",
    "all_price": 90,
    "all_num": 2,
    "items": [
        {
            "_id": ObjectId("5e6f15f1eb57cc45bde81311"),
            "order_id": "2",
            "title": "牛奶",
            "price": 50,
            "num": 1
        },
        {
            "_id": ObjectId("5e6f15faeb57cc45bde81312"),
            "order_id": "2",
            "title": "酸奶",
            "price": 40,
            "num": 1
        }
    ]
}
{
    "_id": ObjectId("5e6f15d4eb57cc45bde8130d"),
    "order_id": "3",
    "uid": 9,
    "trade_no": "333",
    "all_price": 20,
    "all_num": 6,
    "items": [
        {
            "_id": ObjectId("5e6f1603eb57cc45bde81313"),
            "order_id": "3",
            "title": "礦泉水",
            "price": 2,
            "num": 5
        },
        {
            "_id": ObjectId("5e6f160aeb57cc45bde81314"),
            "order_id": "3",
            "title": "毛巾",
            "price": 10,
            "num": 1
        }
    ]
}           

複制