我希望在分组后获得两个$ first和$ last。有可能吗?
这样的事情,但这不起作用:
{ "$group": {
"_id": "type",
"values": [{
"time": { "$first": "$time" },
"value": { "$first": "$value" }
},
{
"time": { "$last": "$time" },
"value": { "$last": "$value" }
}]
}
}
答案 0 :(得分:1)
为了从具有聚合框架的数组中获取$first
和$last
值,您需要首先使用$unwind
将数组“反规范化”为单个文档。还有另一种技巧可以将它们放回阵列中。
假设有这样的文件
{
"type": "abc",
"values": [
{ "time": ISODate("2014-06-12T22:35:42.260Z"), "value": "ZZZ" },
{ "time": ISODate("2014-06-12T22:36:45.921Z"), "value": "KKK" },
{ "time": ISODate("2014-06-12T22:37:18.237Z"), "value": "AAA" }
]
}
假设您的数组已经排序,您可以这样做:
db.junk.aggregate([
{ "$unwind": "$values" },
{ "$group": {
"_id": "$type",
"ftime": { "$first": "$values.time" },
"fvalue": { "$first": "$values.value" },
"ltime": { "$last": "$values.time" },
"lvalue": { "$last": "$values.value" },
}}
])
对于那些数组中的结果,有一个技巧:
db.collection.aggregate([
{ "$unwind": "$values" },
{ "$project": {
"type": 1,
"values": 1,
"indicator": { "$literal": ["first", "last"] }
}},
{ "$group": {
"_id": "$type",
"ftime": { "$first": "$values.time" },
"fvalue": { "$first": "$values.value" },
"ltime": { "$last": "$values.time" },
"lvalue": { "$last": "$values.value" },
"indicator": { "$first": "$indicator" }
}},
{ "$unwind": "$indicator" },
{ "$project": {
"values": {
"time": {
"$cond": [
{ "$eq": [ "$indicator", "first" ] },
"$ftime",
"$ltime"
]
},
"value": {
"$cond": [
{ "$eq": [ "$indicator", "first" ] },
"$fvalue",
"$lvalue"
]
}
}
}},
{ "$group": {
"_id": "$_id",
"values": { "$push": "$values" }
}}
])
如果您的数组未排序,请在第一个$sort
之前放置一个额外的$group
阶段,以确保您的商品符合您希望$first
和{$last
对其进行评估的顺序{3}}。逻辑顺序,其中是“时间”字段,所以:
{ "$sort": { "type": 1, "values.time": 1 } }
$literal
声明一个数组,用于标识“first”和“last”的值,这些值稍后“展开”以创建每个分组文档的两个副本。然后使用$cond
运算符对这些值进行评估,以便为“值”重新分配单个字段,最后使用$push
将其推回到数组中。
请记住,总是首先在管道中尝试$match
,以便将您正在处理的文档数量减少到合理需要的数量。您几乎不想在整个集合中执行此操作,尤其是在阵列上使用$unwind
时。
正如在MongoDB 2.6及更高版本中引入/公开最终注释$literal
一样。对于以前的版本,您可以将其与未记录的 $const
。