我有一个包含日期数组的模型。我使用 $gte
运算符作为查询集合的条件,其中日期数组中的所有元素都是 $gte
给定日期
例如我有这个文件:
{ dates: [
ISODate("2016-10-24T22:00:00.000+0000"),
ISODate("2017-01-16T23:00:00.000+0000")]
}
当我运行此查询{dates: {$gte: new Date()}}
时,它会为我提供整个文档。但我希望得到一个结果,其中每个数组项都匹配我的查询,而不只是一个。
答案 0 :(得分:3)
您可以使用$not
和比较条件的反转来执行此操作:
db.test.find({dates: {$not: {$lt: new Date()}}})
所以这匹配文档,而不是dates
元素的值小于当前时间的情况;换句话说,所有dates
值都是> =当前时间。
答案 1 :(得分:2)
您还可以将聚合框架与 $redact
管道运算符结合使用,该运算符允许您使用 $cond
运算符来处理逻辑条件,使用特殊操作 $$KEEP
来“保留”逻辑条件为真的文档或 $$PRUNE
以“删除”文档所在的条件是假的。
此操作类似于具有 $project
管道,该管道选择集合中的字段并创建一个新字段,其中包含逻辑条件查询的结果,然后是后续的 $match
,但 $redact
使用效率更高的单个管道阶段。
至于逻辑条件,可以使用Set Operators,因为它们允许表达式对数组执行set操作,将数组视为集合。这些运算符中的这些运算符即 $allElementTrue
和 $map
运算符可以用作逻辑条件表达式,因为它们的工作方式是数组中的所有元素实际上都是 $gte
指定的日期,那么这是一个真正的匹配,文档是“保留”的。否则它被“修剪”并丢弃。
考虑以下展示上述概念的例子:
填充测试集
db.test.insert([
{ dates: [
ISODate("2016-10-24T22:00:00.000+0000"),
ISODate("2017-01-16T23:00:00.000+0000")]
} ,
{ dates: [
ISODate("2017-01-03T22:00:00.000+0000"),
ISODate("2017-01-16T23:00:00.000+0000")]
}
])
使用 $redact
db.test.aggregate([
{ "$match": { "dates": { "$gte": new Date() } } },
{
"$redact": {
"$cond": [
{
"$allElementsTrue": {
"$map": {
"input": "$dates",
"as": "date",
"in": { "$gte": [ "$$date", new Date() ] }
}
}
},
"$$KEEP",
"$$PRUNE"
]
}
}
])
示例输出
{
"_id" : ObjectId("581899dda450d81cb7d87d3a"),
"dates" : [
ISODate("2017-01-03T22:00:00.000Z"),
ISODate("2017-01-16T23:00:00.000Z")
]
}
另一种不那么优雅的方法是使用 $where
(作为最后的手段)使用 Array.prototype.every()
方法:
db.test.find({ "$where": function(){
return this.dates.every(function(date) {
return date >= new Date();
})}
})