Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Mongodb中只包含起始日期的数组中,如何获取时间段中与条件匹配的所有元素_Mongodb_Date_Mongodb Query_Aggregation Framework_Event Sourcing - Fatal编程技术网

在Mongodb中只包含起始日期的数组中,如何获取时间段中与条件匹配的所有元素

在Mongodb中只包含起始日期的数组中,如何获取时间段中与条件匹配的所有元素,mongodb,date,mongodb-query,aggregation-framework,event-sourcing,Mongodb,Date,Mongodb Query,Aggregation Framework,Event Sourcing,我收集了以下物品: { id:1, 状态历史记录:[ { 状态:“活动”, 日期:ISODate(“2020-04-26T22:02:26.000Z”) }, { 状态:“已禁用”, 日期:ISODate(“2020-05-20T22:02:26.000Z”) } ] } { id:2, 状态历史记录:[ { 状态:“活动”, 日期:ISODate(“2020-05-26T22:02:26.000Z”) } ] } { id:3, 状态历史记录:[ { 状态:“活动”, 日期:ISODate(“

我收集了以下物品:

{
id:1,
状态历史记录:[
{
状态:“活动”,
日期:ISODate(“2020-04-26T22:02:26.000Z”)
},
{
状态:“已禁用”,
日期:ISODate(“2020-05-20T22:02:26.000Z”)
}
]
}
{
id:2,
状态历史记录:[
{
状态:“活动”,
日期:ISODate(“2020-05-26T22:02:26.000Z”)
}
]
}
{
id:3,
状态历史记录:[
{
状态:“活动”,
日期:ISODate(“2020-04-26T22:02:26.000Z”)
},
{
状态:“已禁用”,
日期:ISODate(“2020-04-27T22:02:26.000Z”)
}
]
}
现在我需要找到所有在2020年5月处于活动状态的项目。数组
statusHistory
仅包含状态更改的日期。我需要以某种方式将这些数组聚合到一个表单中,其中的项也包含到目前为止的内容。比如:

{
状态:“活动”,
日期:ISODate(“2020-04-26T22:02:26.000Z”),//起始日期
dateTo:ISODate(“2020-05-20T22:02:26.000Z”)//它是从数组中下一项的日期开始的
}
然后我想删除该期间之外的所有项目,因此我希望得到以下结果:

{
id:1,
状态历史记录:[
{
状态:“活动”,
日期:ISODate(“2020-04-26T22:02:26.000Z”)
}
]
}
{
id:2,
状态历史记录:[
{
状态:“活动”,
日期: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'
                }
            }
        }
    } },
])

您可以使用
$filter
仅选择与条件匹配的数组元素。在这种情况下,您希望包含所选元素的附加信息,也可以使用
$map
。这两个运算符都用于在聚合查询中处理数组。您可以使用
$reduce
(正如您所说,您已经尝试过的),但是
$filter
是合适的运算符。您可以提供如何操作吗?因为要进行筛选,我仍然需要数组中下一项的日期。我真的不知道如何使用
$map
并从下一项中获取日期。当元素同时包含date from和date to时,很容易做到这一点,但我需要知道如何在元素中不包含to date。若要从数组中的下一个元素获取日期,请首先查找当前元素的索引。将1添加到该索引中,就可以将索引添加到下一个元素。另外,请参见
arrayElemAt
indexOfArray
。感谢它帮助我更新了使用的索引:
{'$add':[{'$indexOfArray':['$statusHistory.date','$$this.date']},1]}
。因此,我首先按日期找到当前元素的索引,然后添加+1。@Saljack很棒的东西,很高兴这有帮助!