【问题标题】:Compare two date fields in MongoDB比较 MongoDB 中的两个日期字段
【发布时间】:2026-01-15 09:45:01
【问题描述】:

在我的收藏中,每个文档都有 2 个日期,已修改和同步。我想找到那些修改过的>同步,或者同步不存在。

我试过了

{'modified': { $gt : 'sync' }}

但它没有显示我的预期。有什么想法吗?

谢谢

【问题讨论】:

    标签: node.js mongodb datetime mongodb-query aggregation-framework


    【解决方案1】:

    您不能将一个字段与另一个字段的值进行正常查询匹配。但是,您可以使用聚合框架来做到这一点:

    db.so.aggregate( [
        { $match: …your normal other query… },
        { $match: { $eq: [ '$modified', '$sync' ] } }
    ] );
    

    我把……你正常的其他查询……放在那里,因为你可以让那个位使用索引。因此,如果您只想对 name 字段为 charles 的文档执行此操作,您可以这样做:

    db.so.ensureIndex( { name: 1 } );
    db.so.aggregate( [
        { $match: { name: 'charles' } },
        { $project: { 
            modified: 1, 
            sync: 1,
            name: 1,
            eq: { $cond: [ { $gt: [ '$modified', '$sync' ] }, 1, 0 ] } 
        } },
        { $match: { eq: 1 } }
    ] );
    

    输入:

    { "_id" : ObjectId("520276459bf0f0f3a6e4589c"), "modified" : 73845345, "sync" : 73234 }
    { "_id" : ObjectId("5202764f9bf0f0f3a6e4589d"), "modified" : 4, "sync" : 4 }
    { "_id" : ObjectId("5202765b9bf0f0f3a6e4589e"), "modified" : 4, "sync" : 4, "name" : "charles" }
    { "_id" : ObjectId("5202765e9bf0f0f3a6e4589f"), "modified" : 4, "sync" : 45, "name" : "charles" }
    { "_id" : ObjectId("520276949bf0f0f3a6e458a1"), "modified" : 46, "sync" : 45, "name" : "charles" }
    

    这会返回:

    {
        "result" : [
            {
                "_id" : ObjectId("520276949bf0f0f3a6e458a1"),
                "modified" : 46,
                "sync" : 45,
                "name" : "charles",
                "eq" : 1
            }
        ],
        "ok" : 1
    }
    

    如果您需要更多字段,您需要将它们添加到$project

    【讨论】:

    • 您确实应该避免使用 $where 变体,因为它通过 Javascript。另外,请接受答案。
    【解决方案2】:

    对于 MongoDB 3.6 及更高版本:

    $expr 运算符允许在查询语言中使用聚合表达式,因此您可以执行以下操作:

    db.test.find({ "$expr": { "$gt": ["$modified", "$sync"] } })
    

    或使用带有$match管道的聚合框架

    db.test.aggregate([
        { "$match": { "$expr": { "$gt": ["$modified", "$sync"] } } }
    ])
    

    对于 MongoDB 3.0+:

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

    考虑运行以下展示上述概念的聚合操作:

    db.test.aggregate([
        { "$redact": {
            "$cond": [
                { "$gt": ["$modified", "$sync"] },
                "$$KEEP",
                "$$PRUNE"
            ]
        } }
    ])
    

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

    【讨论】:

      【解决方案3】:

      简单

      db.collection.find({$where:"this.modified>this.sync"})
      

      例子

      Kobkrits-MacBook-Pro-2:~ kobkrit$ mongo
      MongoDB shell version: 3.2.3
      connecting to: test
      > db.time.insert({d1:new Date(), d2: new Date(new Date().getTime()+10000)})
      WriteResult({ "nInserted" : 1 })
      > db.time.find()
      { "_id" : ObjectId("577a619493653ac93093883f"), "d1" : ISODate("2016-07-04T13:16:04.167Z"), "d2" : ISODate("2016-07-04T13:16:14.167Z") }
      > db.time.find({$where:"this.d1<this.d2"})
      { "_id" : ObjectId("577a619493653ac93093883f"), "d1" : ISODate("2016-07-04T13:16:04.167Z"), "d2" : ISODate("2016-07-04T13:16:14.167Z") }
      > db.time.find({$where:"this.d1>this.d2"})
      > db.time.find({$where:"this.d1==this.d2"})
      > 
      

      【讨论】:

        【解决方案4】:

        使用 Javascript,使用 foreach 并将 Date 转换为 toDateString()

        db.ledgers.find({}).forEach(function(item){
        
            if(item.fromdate.toDateString() == item.todate.toDateString())
            {
                printjson(item)
            }
        })
        

        【讨论】:

          【解决方案5】:

          现在您的查询正在尝试返回所有结果,使得modified 字段大于单词'sync'。尝试去掉 sync 周围的引号,看看是否能解决任何问题。否则,我做了一些研究,发现this question。您尝试做的事情可能无法在单个查询中完成,但是一旦您从数据库中提取所有内容,您应该能够操作您的数据。

          【讨论】:

          • 谢谢@gr3co,我试图避免聚合,但似乎是唯一的出路...... :(
          【解决方案6】:

          要在不聚合的情况下解决此问题,请将您的查询更改为: {'modified': { $gt : ISODate(this.sync) }}

          【讨论】: