最近需要做个统计,计算一个销售或部门(n 个销售),在一段时间内(n 天)的成交数据

每个销售每天一条记录(si_id 和 date 组合索引),data 数组存放了每个产品的成交数量

简单分析后,我们需要得到的就是 data 下每个 product_idnum 之和

在查询出来后,进行循环处理,结果由于数据量太大导致内存溢出。能不能像 MySQL 中直接进行 GROUP BY + SUM() 呢?

数据在 Mongo,大致结构如下:

[
    'si_id' => 1,//销售ID
    'date' => '2019-05-28',//Y-m-d
    'data' => [
        0 => [
            'product_name' => '产品A',
            'product_id' => 1,
            'num' => 123
        ],
        1 => [
            'product_name' => '产品B',
            'product_id' => 2,
            'num' => 123
        ],
        //more..
    ],
]

查看文档后发现了 Mongo 的聚合 Aggregation,其中有几种实现方式

mongo-aggregation

这里分享的是管道方式,Map-Reduce和单用途聚合可以查看官方文档

管道模式顾名思义就是像个 pipeline 一样,经过层层筛选,最终得到你想要的结果

第一阶段

首先使用 $match 添加查询条件,把销售 ID 条件和 时间条件写上:

[
    '$match' => [
        'si_id' => [
            '$in' => [1,2,3,4]
        ],
        'date' => [
            '$gte' => '2019-05-01',
            '$lte' => '2019-05-30'
        ]
    ]
]

第二阶段

如果需要,使用 $project 指定查询列,例如我们想分次查,一次求一个产品的和:

[
    '$project' => [
        'data' => [
            '$filter' => [
                'input' => '$data',
                'as' => 'temp',
                'cond' => [
                    '$eq' => [
                        '$$temp.product_id', 1 //只查询产品ID为1的记录
                    ]
                ]
            ]
        ]
    ]
]

由于我们的数据结构特殊,需要处理数组,所以要加上 $unwind

[
    '$unwind' => '$data'
]

第三阶段

使用 $group 进行求和,也就是我们需要的结果:

[
    '$group' => [
        '_id' => '$data.product_id',
        'num' => [
            '$sum' => '$data.num' //对num字段进行求和
        ]
    ]
]

意犹未尽的你可以再去看看文档,是否能进一步优化你的日常开发

步骤 作用 SQL等价运算符
$match 过滤 WHERE
$project 投影 AS
$sort 排序 ORDER BY
$group 分组 GROUP BY
$skip/$limit 结果限制 SKIP/LIMIT
$lookup 左外连接 LEFT OUTER JOIN

see MongoDB\Collection::aggregate()

PPT