[英]Query where all array items are greater than a specified condition
我有一个包含日期数组的模型。 我使用$gte
运算符作为查询集合的条件,其中日期数组中所有元素都是给定日期的$gte
。
例如,我有此文档:
{ dates: [
ISODate("2016-10-24T22:00:00.000+0000"),
ISODate("2017-01-16T23:00:00.000+0000")]
}
当我运行此查询{dates: {$gte: new Date()}}
,结果就是整个文档。 但是我想要一个结果,其中每个数组项都与我的查询匹配,而不仅仅是一个查询。
您可以使用$not
和比较条件的倒置来实现:
db.test.find({dates: {$not: {$lt: new Date()}}})
因此,这与docs匹配,而不是存在dates
元素的值小于当前时间的情况; 换句话说,所有dates
值都> =当前时间。
您还可以将聚合框架与$redact
管道运算符一起使用,该框架允许您通过$cond
运算符处理逻辑条件,并使用特殊操作$$KEEP
来“保留”逻辑条件为true或$$PRUNE
的文档。在条件为假的情况下“删除”文档。
此操作类似于使用$project
管道来选择集合中的字段,并创建一个新字段来保存逻辑条件查询的结果,然后再保存随后的$match
,除了$redact
使用单个管道阶段,该阶段更高效。
至于逻辑条件,您可以使用Set Operators ,因为它们允许表达式对数组执行set操作,并将数组视为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")]
}
])
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();
})}
})
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.