如何获取仅包含 Mongodb 中日期的数组中时间段内匹配条件的所有元素
How get all elements which match condition in time period in array which contains only from date in Mongodb
我有一个 collection,其中包含以下项目:
{
id: 1,
statusHistory: [
{
status: "ACTIVE",
date: ISODate("2020-04-26T22:02:26.000Z")
},
{
status: "DISABLED",
date: ISODate("2020-05-20T22:02:26.000Z")
}
]
}
{
id: 2,
statusHistory: [
{
status: "ACTIVE",
date: ISODate("2020-05-26T22:02:26.000Z")
}
]
}
{
id: 3,
statusHistory: [
{
status: "ACTIVE",
date: ISODate("2020-04-26T22:02:26.000Z")
},
{
status: "DISABLED",
date: ISODate("2020-04-27T22:02:26.000Z")
}
]
}
现在我需要找到 2020 年 5 月状态为 ACTIVE 的所有项目。数组 statusHistory
仅包含状态更改的日期。我需要以某种方式将这些数组聚合成一种形式,其中的项目也包含最新信息。类似于:
{
status: "ACTIVE",
date: ISODate("2020-04-26T22:02:26.000Z"), // from
dateTo: ISODate("2020-05-20T22:02:26.000Z") // it is from the date of the next item in the array
}
然后我想删除该期间内的所有项目,所以我想要这个结果:
{
id: 1,
statusHistory: [
{
status: "ACTIVE",
date: ISODate("2020-04-26T22:02:26.000Z")
}
]
}
{
id: 2,
statusHistory: [
{
status: "ACTIVE",
date: ISODate("2020-05-26T22:02:26.000Z")
}
]
}
我考虑过使用某种方法 $reduce
但我没有找到解决方案。在我看来,这是事件溯源模式中的一个常见问题,但我找不到解决方法。
以下管道可能不是最好的,但值得一试。将用一些解释更新它,但如果你得到意外的结果,帮助理解管道或调试它,运行 聚合只是第一个管道步骤。例如,运行 mongo shell 中的聚合为:
db.collection.aggregate([
{ '$addFields': { .... } }
])
检查结果以查看新 statusHistory
数组是否使用新字段 dateTo
正确构建。如果这给出了预期的结果,请添加下一个:
db.collection.aggregate([
{ '$addFields': { .... } },
{ '$match': { ... } }
])
总的来说,运行 操作
db.collection.aggregate([
{ '$addFields': {
'statusHistory': {
'$map': {
'input': '$statusHistory',
'in': {
'$mergeObjects': [
'$$this',
{ 'dateTo': {
'$arrayElemAt': [
'$statusHistory',
{ '$indexOfArray': [
'$statusHistory.status',
'DISABLED'
] }
]
} }
]
}
}
}
} },
{ '$match': {
'$expr': {
'$gt': [
{ '$size': {
'$filter': {
'input': '$statusHistory',
'cond': {
'$and': [
{ '$eq': ['$$this.status', 'ACTIVE'] },
{ '$gte': ['$$this.dateTo.date', new Date('2020-05-01')] }
]
}
}
} },
0
]
}
} },
{ '$addFields': {
'statusHistory': {
'$map': {
'input': {
'$filter': {
'input': '$statusHistory',
'as': 'item',
'cond': { '$eq': ['$$item.status', 'ACTIVE'] }
}
},
'in': {
'status': '$$this.status',
'date': '$$this.date'
}
}
}
} },
])
我有一个 collection,其中包含以下项目:
{
id: 1,
statusHistory: [
{
status: "ACTIVE",
date: ISODate("2020-04-26T22:02:26.000Z")
},
{
status: "DISABLED",
date: ISODate("2020-05-20T22:02:26.000Z")
}
]
}
{
id: 2,
statusHistory: [
{
status: "ACTIVE",
date: ISODate("2020-05-26T22:02:26.000Z")
}
]
}
{
id: 3,
statusHistory: [
{
status: "ACTIVE",
date: ISODate("2020-04-26T22:02:26.000Z")
},
{
status: "DISABLED",
date: ISODate("2020-04-27T22:02:26.000Z")
}
]
}
现在我需要找到 2020 年 5 月状态为 ACTIVE 的所有项目。数组 statusHistory
仅包含状态更改的日期。我需要以某种方式将这些数组聚合成一种形式,其中的项目也包含最新信息。类似于:
{
status: "ACTIVE",
date: ISODate("2020-04-26T22:02:26.000Z"), // from
dateTo: ISODate("2020-05-20T22:02:26.000Z") // it is from the date of the next item in the array
}
然后我想删除该期间内的所有项目,所以我想要这个结果:
{
id: 1,
statusHistory: [
{
status: "ACTIVE",
date: ISODate("2020-04-26T22:02:26.000Z")
}
]
}
{
id: 2,
statusHistory: [
{
status: "ACTIVE",
date: ISODate("2020-05-26T22:02:26.000Z")
}
]
}
我考虑过使用某种方法 $reduce
但我没有找到解决方案。在我看来,这是事件溯源模式中的一个常见问题,但我找不到解决方法。
以下管道可能不是最好的,但值得一试。将用一些解释更新它,但如果你得到意外的结果,帮助理解管道或调试它,运行 聚合只是第一个管道步骤。例如,运行 mongo shell 中的聚合为:
db.collection.aggregate([
{ '$addFields': { .... } }
])
检查结果以查看新 statusHistory
数组是否使用新字段 dateTo
正确构建。如果这给出了预期的结果,请添加下一个:
db.collection.aggregate([
{ '$addFields': { .... } },
{ '$match': { ... } }
])
总的来说,运行 操作
db.collection.aggregate([
{ '$addFields': {
'statusHistory': {
'$map': {
'input': '$statusHistory',
'in': {
'$mergeObjects': [
'$$this',
{ 'dateTo': {
'$arrayElemAt': [
'$statusHistory',
{ '$indexOfArray': [
'$statusHistory.status',
'DISABLED'
] }
]
} }
]
}
}
}
} },
{ '$match': {
'$expr': {
'$gt': [
{ '$size': {
'$filter': {
'input': '$statusHistory',
'cond': {
'$and': [
{ '$eq': ['$$this.status', 'ACTIVE'] },
{ '$gte': ['$$this.dateTo.date', new Date('2020-05-01')] }
]
}
}
} },
0
]
}
} },
{ '$addFields': {
'statusHistory': {
'$map': {
'input': {
'$filter': {
'input': '$statusHistory',
'as': 'item',
'cond': { '$eq': ['$$item.status', 'ACTIVE'] }
}
},
'in': {
'status': '$$this.status',
'date': '$$this.date'
}
}
}
} },
])