我在mongodb集合中有以下一系列订单:
id date value
A 1 Jan 18 1
A 2 Jan 18 0
A 3 Jan 18 0
B 14 Jan 18 4
B 15 Jan 18 5
B 16 Jan 18 0
使用mongodb聚合管道(mongo 3.4),我试图找出每个id,值的日期从非零变为0,以及这些记录的“ id组”。 >
第二次更新:19年5月26日
我已经更新了问题,以使第一个,最后一个实现看起来更清晰:
{
"$addFields": {
"date": {
"$dateFromString": {
"dateString": "$date"
}
}
}
},
{
$group: {
_id: {
"id": "$id",
"value": "$value"
},
"first": {
"$first": "$date"
},
"last": {
"$last": "$date"
}
}
},
{
"$match": {
"_id.value": 0
}
}
https://mongoplayground.net/p/moBRI2Q7aGu
这给了我
id value first last
A 0 2 Jan 18 3 Jan 18
B 0 16 Jan 18 16 Jan 18
如果我查看“第一个”日期,那是那些值首先从非零变为0的日期。
但是,我希望看到在某个时间点从非零变为0的那些值的整个“ id组”。所以:
id value first last
A 1 1 Jan 18 1 Jan 18
A 0 2 Jan 18 3 Jan 18
B 4 14 Jan 18 14 Jan 18
B 5 15 Jan 18 15 Jan 18
B 0 16 Jan 18 16 Jan 18
要获取此信息,我需要在上述管道匹配之前访问group阶段,所以https://mongoplayground.net/p/YTP-NBJtO4R,并使用第一个聚合管道的结果集对此进行过滤。我是通过第一个结果集上的左联接在熊猫中执行此操作的,但这似乎不太好。
所以现在我有两个不同的管道,这似乎有点不方便。理想情况下,最后一个结果集将来自单个聚合管道。
答案 0 :(得分:2)
您可以使用以下汇总
db.collection.aggregate([
{ "$addFields": {
"date": { "$dateFromString": { "dateString": "$date" }}
}},
{ "$sort": { "date": 1 }},
{ "$match": { "value": 0 }},
{ "$group": {
"_id": "$id",
"date": { "$first": "$date" },
"value": { "$first": "$value" }
}}
])
更多聚合技巧
db.collection.aggregate([
{ "$match": { "value": "0" }},
{ "$addFields": {
"date": { "$dateFromString": { "dateString": "$date" }}
}},
{ "$sort": { "date": 1 }},
{ "$group": {
"_id": "$id",
"data": {
"$push": {
"value": "$value",
"date": "$date"
}
}
}},
{ "$project": {
"data": {
"$arrayElemAt": [
{ "$filter": {
"input": "$data",
"cond": { "$eq": ["$$this.value", "0"] }
}},
0
]
}
}},
{ "$replaceRoot": {
"newRoot": { "$mergeObjects": [{ "id": "$_id" }, "$data"] }
}}
])
如果文档已经包含日期格式(而不是上面显示的方式)的日期,则可以删除第一阶段$addFields
。
答案 1 :(得分:1)
首先按ID分组,以便我们可以单独处理每个“订单”:
{
$group: {
_id: "$id",
date_x_value: {$push: {date: "$date", value: "$value"}},
sum: {$sum: "$value"}
}
}
现在仅匹配相关文档:
{
$match: {
$and: [ {"date_x_value.value": 0}, {sum: {$gt: 0}}]
}
}
按照日期排序:
{
$sort: {
"date_x_value.date": 1
}
}
现在进行实际查询:
{ $addFields:
{
matches: {
$reduce: {
input: "$date_x_value",
initialValue: {"last_value": 0, "dates": []},
in: {
last_value: "$$this.value",
dates: { $concatArrays : [
{
$cond:{
if: {$and: [{$gt: ["$$value.last_value", 0]}, {$eq: ["$$this.value", 0]}]},
then: ["$$this.date"],
else: []
}
}, "$$value.dates"]
}
}
}
}
}
}
这将返回一个日期数组,请注意,日期是0以后的日期。 这两个文档的含义:
date: Jan 1, value: 4
date: Jan 2, value: 0
该数组将包含1月2日。
编辑**:请注意,我并没有完全尝试优化查询 ,以提高可读性,如果这是一个问题,则应优化第一个根据集合的索引在主查询之前的部分。