Javascript 从日期早于今天的数组聚合
我正在尝试聚合具有数组的集合。在这个数组中,有一个Javascript 从日期早于今天的数组聚合,javascript,mongodb,mongodb-query,aggregation-framework,Javascript,Mongodb,Mongodb Query,Aggregation Framework,我正在尝试聚合具有数组的集合。在这个数组中,有一个提醒数组。文档可能如下所示: { _id: "1234", dates: { start: ISODate(), end: ISODate() }, reminders: [{ sendAt: ISODate(), status: 'closed' }, { sendAt: ISODate(), status: 'open' }] } 假设第一个在今天之前,下一个在今天之后
提醒
数组。文档可能如下所示:
{
_id: "1234",
dates: {
start: ISODate(),
end: ISODate()
},
reminders: [{
sendAt: ISODate(),
status: 'closed'
}, {
sendAt: ISODate(),
status: 'open'
}]
}
假设第一个在今天之前,下一个在今天之后。我想做的是获取今天之前所有的数组,或者,如果今天之前没有任何数组,则获取一个空数组。我尝试了以下方法
db.reminders.aggregate([
{ $match: { 'dates.end': { $gt: new Date } } },
{ $unwind: '$reminders' },
{
$match: {
reminders: {
$elemMatch: {
sendAt: { $lt: new Date() },
status: { $ne: 'open' }
}
}
}
}
])
然而,如果在今天之前没有提醒,它将失败,并且没有任何回报
有没有一种方法可以通过mongodb聚合来构建此结构
注意:我不能使用$filter
,因为这是在3.2中的您可以使用操作符来筛选出版本=2.6
的子文档。
它还避免了不必要的$unwind
阶段
所有具有$match
属性大于搜索条件日期的文档。end
遍历所有子文档,并在符合条件的文档中执行以下操作,否则$redact
var endDateToMatch = ISODate("2014-01-01T00:00:00Z");
var currentDate = ISODate();
db.t.aggregate([
{
$match:{"dates.end":{$gt:endDateToMatch}}
},
{
$redact:{$cond:[
{$and:[
{$ne:[{$ifNull:["$status",""]},
"open"]},
{$lt:[{$ifNull:["$sendAt",currentDate-1]},
currentDate]}
]
},
"$$DESCEND","$$PRUNE"]}
}
])
这将为每个与$match
阶段匹配的文档提供一个文档。如果需要累加所有子文档,则需要通过\u id
将$unwind
“提醒”和$group
作为null
筛选出=2.6版本的子文档。
它还避免了不必要的$unwind
阶段
$match
所有具有日期的文档。end
属性大于搜索条件
$redact
遍历所有子文档,并在符合条件的文档中执行以下操作,否则
示例代码:
var endDateToMatch = ISODate("2014-01-01T00:00:00Z");
var currentDate = ISODate();
db.t.aggregate([
{
$match:{"dates.end":{$gt:endDateToMatch}}
},
{
$redact:{$cond:[
{$and:[
{$ne:[{$ifNull:["$status",""]},
"open"]},
{$lt:[{$ifNull:["$sendAt",currentDate-1]},
currentDate]}
]
},
"$$DESCEND","$$PRUNE"]}
}
])
这将为每个与$match
阶段匹配的文档提供一个文档。如果需要累积所有子文档,则需要通过\u id
将$diswind
和$group
作为null
,因此基本上需要$filter
行为,但需要在早期版本中执行此操作,主案例是返回文档,即使数组内容最终为空
对于MongoDB 2.6,您可以使用和执行“几乎”相同的操作:
db.remements.aggregate([
{“$match”:{“dates.end”:{“$gt”:new Date()}},
{“$project”:{
“日期”:1,
“提醒”:{
“$setDifference”:[
{“$map”:{
“输入”:“$提醒”,
“作为”:“提醒”,
“在”:{
“$cond”:[
{“$and”:[
{“$lt”:[“$$remention.sendAt”,new Date()]},
{“$ne”:[“$$REMENTER.status”,“open”]}
]},
“$$提醒”,
假的
]
}
}},
[错误]
]
}
}}
])
只要从$setDifference
得到的“set”都是不正确识别的项,这就可以了。因此,$map
方法应用测试,如果条件不匹配,则返回内容或false
。$setdifference
基本上从结果中删除了任何false
元素,但当然,作为一个“集合”,任何项的计数都与一项完全相同
如果您的MongoDB小于2.6(或者“集合”的情况使上述内容无法使用),那么在查看要过滤的内容时只需更加小心:
db.remements.aggregate([
{“$match”:{“dates.end”:{“$gt”:new Date()}},
{“$解除”:“$提醒”},
//计算条件匹配的位置
{“$组”:{
“\u id”:“$\u id”,
“日期”:{“$first”:“$dates”},
“提醒”:{“$push”:“$REMENTERS”},
“匹配”:{“$sum”:{
“$cond”:[
{“$and”:[
{“$lt”:[“$remements.sendAt”,new Date()]},
{“$ne”:[“$members.status”,“open”]}
]},
1.
0
]
}}
}},
//为简洁起见,替换不计数的数组
{“$project”:{
“日期”:1,
“提醒”:{“$cond”:[
{“$eq”:[“$matched”,0]},
{“$const”:[false]},
“$提醒”
]},
“匹配”:1
}},
//再次放松
{“$解除”:“$提醒”},
//筛选没有要保留的匹配项的“或”
{“$match”:{
“$or”:[
{
“remention.sendAt”:{“$lt”:new Date()},
“提醒.状态:{“$ne”:“打开”}
},
{“匹配”:0}
]
}},
//再次分组
{“$组”:{
“\u id”:“$\u id”,
“日期”:{“$first”:“$dates”},
“提醒”:{“$push”:“$REMENTERS”}
}},
//将[false]数组替换为空数组
{“$project”:{
“日期”:1,
“提醒”:{“$cond”:[
{“$eq”:[“$rementers”,[false]]},
{“$const”:[]},
“$提醒”
]}
}}
])
这有点冗长,但基本上是做同样的事情
还要注意的是,$elemMatch
在处理$unwind
后不适用,因为内容实际上不再是数组。简单的点表示法适用于现在单个文档中的元素。因此您基本上想要$filter
行为,但需要在早期版本中执行此操作,主要情况是返回文档,即使数组内容最终为空
对于MongoDB 2.6,您可以使用和执行“几乎”相同的操作:
db.remements.aggregate([
{“$match”:{“dates.end”:{”$