【问题标题】:Query where all array items are greater than a specified condition查询所有数组项都大于指定条件的位置
【发布时间】:2017-03-14 15:29:15
【问题描述】:

我有一个模型,其中包含一个带日期的数组。我使用 $gte 运算符作为条件来查询日期数组中的所有元素都是 $gte 给定日期的集合。

例如我有这个文件:

{ dates: [
    ISODate("2016-10-24T22:00:00.000+0000"), 
    ISODate("2017-01-16T23:00:00.000+0000")]
} 

当我运行此查询{dates: {$gte: new Date()}} 时,它会为我提供整个文档作为结果。但我想要一个结果,其中每个数组项都与我的查询匹配,而不仅仅是一个。

【问题讨论】:

  • 你到底是什么意思?
  • 未明确的问题,请更具体并添加更多详细信息,以便有人可以帮助您。
  • @GandalftheWhite 我想查询数组中的所有元素,并匹配查询。现在即使数组中的一个元素与查询匹配,它也会返回文档。
  • 只有当搜索查询与数组中的值匹配时,您才需要文档的值,这就是您想要的吗?

标签: arrays node.js mongodb mongoose mongodb-query


【解决方案1】:

您可以通过使用$not 和您的比较条件的反转来做到这一点:

db.test.find({dates: {$not: {$lt: new Date()}}})

所以这匹配文档,其中不存在值小于当前时间的dates 元素;换句话说,所有dates 值都>= 当前时间。

【讨论】:

  • 相当聪明 ;)
【解决方案2】:

您还可以将聚合框架与 $redact 管道运算符一起使用,它允许您使用 $cond 运算符处理逻辑条件并使用特殊操作$$KEEP“保留”逻辑条件为真的文档或$$PRUNE“删除”条件为假的文档。

此操作类似于具有 $project 管道,它选择集合中的字段并创建一个新字段来保存逻辑条件查询的结果,然后是后续 @ 987654326@,除了 $redact 使用更高效的单个流水线阶段。

至于逻辑条件,您可以使用Set Operators,因为它们允许对数组执行集合操作的表达式,将数组视为集合。这两个运算符即 $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$setEquals

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();
    })}
})

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-02
    • 2021-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多