MongoDB 高级查询 aggregate 聚合管道

2020-11-26 12:30:01 浏览数 (1)

1. MongoDB 聚合管道简介

使用聚合管道可以对集合中的文档进行变换和组合,常用于多表关联查询、数据的统计。

db.COLLECTION_NAME.aggregate() 方法用来构建和使用聚合管道,下图是官网给的实例,可以看出来聚合管道的用法还是比较简单的。

2. MongoDB Aggregation 管道操作符与表达式

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

MySQL 和 MongoDB 的聚合 对比 :

管道操作符作为 “ 键 ”, 所对应的“ 值 ”叫做管道表达式, 如 {$match:{status:"A"}} , $match 称为管道操作符,而 status:"A"称为管道表达式,每个管道表达式是一个文档结构,它是由字段名、字段值、和一些表达式操作符组成的,常用的表达式操作符有以下这些。

3. 模拟数据

为了说明每个管道操作符的作用,将以下面数据为参考,分别有order和order_item两个集合。

order集合里的数据

代码语言:javascript复制
{
    "_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集合里的数据

代码语言:javascript复制
{
    "_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 字段。

代码语言:javascript复制
db.order.aggregate([
    {
        $project:{ trade_no:1, all_price:1 }
    }
])

执行结果:

代码语言:javascript复制
{ "_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的记录。

代码语言:javascript复制
db.order.aggregate([
    { 
        $project: { trade_no: 1, all_price: 1}
    },
    { 
        $match: {
            "all_price": {$gte: 90}
        }
    }
])

执行结果:

代码语言:javascript复制
{ "_id" : ObjectId("5e6f15c1eb57cc45bde8130b"), "trade_no" : "111", "all_price" : 100 }

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

6. 管道操作符 $group

将集合中的文档进行分组,可用于统计结果。

例:统计每个订单的订单数量,按照订单号分组。

代码语言:javascript复制
db.order_item.aggregate([
    {   
        $group: 
            {_id: "$order_id", total: {$sum: "$num"}
        }
    }
])

执行结果:

代码语言:javascript复制
{ "_id" : "2", "total" : 2 }

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

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

7. 管道操作符 $sort

将集合中的文档进行排序。

例:要求查找 order 集合, 只返回文档中 trade_no 和 all_price 字段,只显示 all_price 大于等于90的记录,并以all_price进行降序排列。

代码语言:javascript复制
db.order.aggregate([
    { 
        $project: { trade_no: 1, all_price: 1}
    },
    { 
        $match: {
            "all_price": {$gte: 90}
        }
    },
    { 
        $sort: {"all_price": -1}
    }
])

执行结果:

代码语言:javascript复制
{ "_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条记录。

代码语言:javascript复制
db.order.aggregate([
    { 
        $project: { trade_no: 1, all_price: 1}
    },
    { 
        $match: {
            "all_price": {$gte: 90}
        }
    },
    { 
        $sort: {"all_price": -1}
    },
    { 
        $limit: 1
    }
])

执行结果:

代码语言:javascript复制
{ "_id" : ObjectId("5e6f15c1eb57cc45bde8130b"), "trade_no" : "111", "all_price" : 100 }

9. 管道操作符 $skip

对查询结果跳过几条记录进行显示。

例:要求查找 order 集合,只返回文档中 trade_no 和 all_price 字段,只显示 all_price 大于等于90的记录,以 all_price 进行降序排列,并跳过1条记录显示其结果。

代码语言:javascript复制
db.order.aggregate([
    { 
        $project: { trade_no: 1, all_price: 1}
    },
    { 
        $match: {
            "all_price": {$gte: 90}
        }
    },
    { 
        $sort: {"all_price": -1}
    },
    { 
        $skip: 1
    }
])

执行结果:

代码语言:javascript复制
{ "_id" : ObjectId("5e6f15cbeb57cc45bde8130c"), "trade_no" : "222", "all_price" : 90 }

10. 管道操作符 $lookup

对要查询的结果时行多表关联查询。

例:查询 order 集合,关联到order_item集合,将 order 中 order_id 与 order_item 中order_id 相同的记录显示出来,并将结果取名为 items。

代码语言:javascript复制
db.order.aggregate([
    { 
        $lookup: { 
            from: "order_item", 
            localField: "order_id", 
            foreignField: "order_id", 
            as: "items"
        }
    }
])

执行结果:

代码语言:javascript复制
{
    "_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
        }
    ]
}

0 人点赞