具有不同 $match 的嵌套 $group
Posted
技术标签:
【中文标题】具有不同 $match 的嵌套 $group【英文标题】:Nested $group with different $match 【发布时间】:2020-01-11 17:15:18 【问题描述】: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】:我们可以在不使用$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
字段获取的时间之间的差异来分配的。如果差值小于 604800000 毫秒。 (相当于 7 天的毫秒数)表示文档位于最近 7 天,依此类推。
第二阶段:展开标签
Satge III:过滤掉空标签
第四阶段:根据[name, tag]
进行分组,计算最小值、最大值、平均值和音量。
第五阶段:仅基于name
进行分组,并将所有标签和相关数据作为键值对推送到数组中
第六阶段:将键值对数组转化为对象
阶段 VII 和 VIII: 必要的格式
【讨论】:
以上是关于具有不同 $match 的嵌套 $group的主要内容,如果未能解决你的问题,请参考以下文章