我的文件如下:
{
category: "1",
timestamp: ISODate("2016-07-16T00:00:00.000Z"),
amount: 0
},
{
category: "1",
timestamp: ISODate("2016-08-18T00:00:00.000Z"),
amount: 15
},
{
category: "1",
timestamp: ISODate("2016-08-01T00:00:00.000Z"),
amount: 5
},
{
category: "2",
timestamp: ISODate("2016-08-18T00:00:00.000Z"),
amount: 10
}
现在我想按类别第一次分组(已经有效):
{ "$match" : { "timestamp" : { "$gt" : FROM , "$lt" : TO }}},
{ "$sort" : { "timestamp" : 1 }},
{ "$group" : {
"_id" : "$category",
"data" : { "$push" : { "timestamp" : "$timestamp" , "amount" : "$amount" }}
}}
然后将这些对象分组到data
数组中。要获得每周最高金额(或月份 - 取决于用户输入)。
结果应该是这样的(按月分组):
{
_id: "1",
data: [
{
timestamp: "2016-07", // could also be an ISODate with
amount: 0 // first (or last) day of month
}, // if that makes things easier
{
timestamp: "2016-08",
amount: 15
}
]
},
{
_id: "2",
data: [
{
timestamp: "2016-08",
amount: 10
}
]
}
我尝试unwind
data
数组然后重新分组,但这导致了一团糟。
希望您有一些好主意/解决方案来实现这一目标。
编辑:附加问题:
我在category
上放了一个索引,对$match
起作用。在timestamp
上放置一个索引进行排序(因为插入顺序可能与时间戳顺序不同)或者这个索引在聚合中是否有任何影响会不会有用呢?
答案 0 :(得分:3)
我已经接受了Styvane的回答(再次感谢!)并简化了一下:
{$match: { timestamp: { $gt: FROM , $lt: TO }}},
{$group: {
_id: {
id: "$category",
timestamp: { $concat: [
{ $toLower: { $year:"$timestamp" } },
"-",
{ $toLower: { $month: "$timestamp" } }
] }
},
amount: { $max: "$amount" }
}},
{$sort: { "_id.timestamp": 1 } },
{$group: {
_id: "$_id.id",
data: { $push: { timestamp: "$_id.timestamp", amount: "$amount" } }
}}
我在第一个$sort
之前尝试$group
,但这确实给出了意想不到的结果。虽然我只是将$sort
放在$group
个阶段之间。这样,timestamp
上的索引就不再重要了。
答案 1 :(得分:1)
在$sort
阶段之后,您需要$group
by" category"然后$unwind
"数据"领域。
var group1 = { "$group": {
"_id": "$category",
"data": {
"$push": {
"timestamp": "$timestamp",
"amount": "$amount"
}
}
}};
var unwind = { "$unwind": "$data"};
从那里开始,您需要重新$group
您的文档,但这次您不仅需要考虑timestamp
字段,还需要考虑_id
字段,并在此帮助下$toLower
运算符,您可以将年和月值转换为可以使用$concat
运算符连接的字符串。
您还可以使用$sum
返回该组的总和。
var group2 = { "$group": {
"_id": {
"id": "$_id",
"timestamp": {
"$concat": [
{ "$toLower": { "$year": "$data.timestamp" } },
"-",
{ "$toLower": { "$month": "$data.timestamp" } }
]
}},
"amount": { "$sum": "$data.amount" }
}}
最后一个阶段是另一个$group
阶段,您只需按先前的_id.id
值对文档进行分组,然后使用$push
累加器运算符返回数据数组。
var group3 = { "$group": {
"_id": "$_id.id",
"data": {
"$push": {
"timestamp": "$_id.timestamp",
"amount": "$amount"
}
}
}};
您的最终管道将如下所示:
db.collection.aggregate(
[
// $match and `$sort here
group1,
unwind,
group2,
group3
]
)
使用$facet
运算符即可在即将推出的MongoDB版本中改进此查询。
db.collection.aggregate([
// $match and `$sort here
{ "$facet": { "data": [ group1, unwind, group2, group3 ] }
])