具有不同$ match的嵌套$ group

时间:2019-09-09 23:56:02

标签: mongodb mongoose aggregation-framework

Mongo可以汇总以下数据:

{price: 100, name: 'itemA', date: '2019-09-09 00:01:10.534Z'},
{price: 150, name: 'itemA', date: '2019-08-09 00:01:10.534Z'},
{price: 50, name: 'itemA', date: '2019-07-09 00:01:10.534Z'},
{price: 50, name: 'itemA', date: '2019-07-06 00:01:10.534Z'},
{price: 200, name: 'itemB', date: '2019-09-09 00:01:10.534Z'}

进入如下所示的文档:

[
    {
        'name': 'itemA',
        'last_7_days': {
            //sale stats from the last 7 days
            'min': 100,
            'max': 100,
            'avg': 100,
            'volume': 1
        },
        'last_30_days': {
            //sale stats from the last 30 days
            'min': 100,
            'max': 150,
            'avg': 125,
            'volume': 2
        },
        'last_90_days': {
            //sale stats from the last 90 days
            'min': 50,
            'max': 150,
            'avg': 87.5,
            'volume': 4
        },
        'sales': [
            //show recent sales (limit 3)
            {
                'price': 100,
                'date': '2019-09-09 00:01:10.534Z'
            },
            {
                'price': 150,
                'date': '2019-08-09 00:01:10.534Z'
            },
            {
                'price': 50,
                'date': '2019-07-09 00:01:10.534Z'
            }
            
        ]
    },
    {
        'name': 'itemB',
        'last_7_days': {
            //sale stats from the last 7 days
            'min': 200,
            'max': 200,
            'avg': 200,
            'volume': 1
        },
        'last_30_days': {
            //sale stats from the last 30 days
            'min': null,
            'max': null,
            'avg': null,
            'volume': 0
        },
        'last_90_days': {
            //sale stats from the last 90 days
            'min': null,
            'max': null,
            'avg': null,
            'volume': 0
        },
        'sales': [
            //show recent sales (limit 3)
            {
                'price': 200,
                'date': '2019-09-09 00:01:10.534Z'
            }
        ]
    }
]
 

我主要使用$facet进行了尝试,但是到目前为止,我还无法合并代码。只需一个查询,mongo甚至可以输出此输出吗?

任何想法如何进行我提到的输出?任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:0)

我们可以在不使用$facet的情况下执行此操作。想法是标记每个文档是否存在于过去7天,30天和90天,然后根据分配的标签对它们进行分组。

以下是示例:

db.collection.aggregate([
    {
        $addFields:{
            "info":{
                $let:{
                    "vars":{
                        "time_difference":{
                            $subtract:[
                                new Date(),
                                {
                                    $toDate:"$date"
                                }
                            ]
                        }
                    },
                    "in":{
                        "tags":[
                            {
                                $cond:[
                                    {
                                        $lte:["$$time_difference",604800000]
                                    },
                                    "last_7_days",
                                    ""
                                ]
                            },
                            {
                                $cond:[
                                    {
                                        $lte:["$$time_difference",2592000000]
                                    },
                                    "last_30_days",
                                    ""
                                ]
                            },
                            {
                                $cond:[
                                    {
                                        $lte:["$$time_difference",7776000000]
                                    },
                                    "last_90_days",
                                    ""
                                ]
                            }
                        ]
                    }
                }
            }
        }
    },
    {
        $unwind:"$info.tags"
    },
    {
        $match:{
            "info.tags":{
                $ne:""
            }
        }
    },
    {
        $group:{
            "_id":{
                "name":"$name",
                "tag":"$info.tags"
            },
            "name":{
                $first:"$name"
            },
            "tag":{
                $first:"$info.tags"
            },
            "max":{
                $max:"$price"
            },
            "min":{
                $min:"$price"
            },
            "avg":{
                $avg:"$price"
            },
            "volume":{
                $sum:1
            }
        }
    },
    {
        $group:{
            "_id":"$name",
            "name":{
                $first:"$name"
            },
            "info":{
                $push:{
                    "k":"$tag",
                    "v":{
                        "max" : "$max",
                        "min" : "$min",
                        "avg" : "$avg",
                        "volume" : "$volume"
                    }
                }
            }
        }
    },
    {
        $addFields:{
            "info":{
                $arrayToObject:"$info"
            }
        }
    },
    {
        $addFields:{
            "info.name":"$name"
        }
    },
    {
        $replaceRoot:{
            "newRoot":"$info"
        }
    }
]).pretty()

数据集:

{
    "_id" : ObjectId("5d7715b7f04b490307453d02"),
    "price" : 100,
    "name" : "itemA",
    "date" : "2019-09-09T00:01:10.534Z"
}
{
    "_id" : ObjectId("5d7715b7f04b490307453d03"),
    "price" : 150,
    "name" : "itemA",
    "date" : "2019-08-09T00:01:10.534Z"
}
{
    "_id" : ObjectId("5d7715b7f04b490307453d04"),
    "price" : 50,
    "name" : "itemA",
    "date" : "2019-07-09T00:01:10.534Z"
}
{
    "_id" : ObjectId("5d7715b7f04b490307453d05"),
    "price" : 50,
    "name" : "itemA",
    "date" : "2019-07-06T00:01:10.534Z"
}
{
    "_id" : ObjectId("5d7715b7f04b490307453d06"),
    "price" : 200,
    "name" : "itemB",
    "date" : "2019-09-09T00:01:10.534Z"
}

输出:

{
    "last_7_days" : {
        "max" : 100,
        "min" : 100,
        "avg" : 100,
        "volume" : 1
    },
    "last_30_days" : {
        "max" : 100,
        "min" : 100,
        "avg" : 100,
        "volume" : 1
    },
    "last_90_days" : {
        "max" : 150,
        "min" : 50,
        "avg" : 87.5,
        "volume" : 4
    },
    "name" : "itemA"
}
{
    "last_30_days" : {
        "max" : 200,
        "min" : 200,
        "avg" : 200,
        "volume" : 1
    },
    "last_90_days" : {
        "max" : 200,
        "min" : 200,
        "avg" : 200,
        "volume" : 1
    },
    "last_7_days" : {
        "max" : 200,
        "min" : 200,
        "avg" : 200,
        "volume" : 1
    },
    "name" : "itemB"
}

查询分析:

  • 第一阶段::在每个文档中添加标签。标签可以是“ last_7_days”,“ last_30_days”和“ last_90_days”。这些标签是根据当前时间和从date字段中获取的时间之间的差异分配的。如果差异小于6048000000毫秒。 (相当于7天的毫秒数)表示文档位于最近7天之内,依此类推。
  • 第二阶段:展开标签
  • Satge III:过滤出​​空标签
  • 阶段IV::基于[name, tag]进行分组并计算最小,最大,平均和体积。
  • 阶段V::仅基于name进行分组,并将所有标签和相关数据作为键值对推入数组
  • 阶段VI::将键值对数组转换为对象
  • 第七阶段和第八阶段:必要的格式