【问题标题】:How does one properly increment many dates in mongoDB?如何在 mongoDB 中正确地增加许多日期?
【发布时间】:2021-07-14 00:45:52
【问题描述】:

不是一个特别强大的 Javascript 人,我在尝试更新 Mongo 中的大量 Date 对象时遇到了一些麻烦。

好像是$inc has not yet been implemented for Date objects。因此,为了尝试按一天增加一堆日期,我通过 mongo myScript.js 从 bash 调用(类似于)这个脚本:

conn = new Mongo();
db   = conn.getDB('myDatabase');

var incrementDates = function() {
  db.blah.find(myQuery).forEach(function(doc) {

    db.blah.update(
       { _id     : doc._id
       , my_date : { $exists : true }
       }
     , { $set : { my_date : new Date(doc.my_date.getTime() + 86400000) }}
    );

  });
}

incrementDates();

基本思想似乎在 mongoDB shell 中运行良好:

> var doc = db.blah.findOne(myQuery)
> doc.my_date
ISODate("1962-11-02T23:00:00Z")
> new Date(doc.my_date.getTime() + 86400000);
ISODate("1962-11-03T23:00:00Z")

但在脚本中不是很好:

TypeError: doc.my_date has no properties

所以我认为我正在尝试在某处的null 上调用getTime,即使我的更新中的查询应该只返回存在my_date 的文档。

关于这里发生了什么的任何想法?更重要的是:有没有更好的方法来做到这一点?

【问题讨论】:

  • 疑难解答建议:您是否尝试过在执行 db.blah.update 之前输出 doc.my_date?它可以告诉你它阻塞的 my_date 的值是多少。
  • @Philipp 嘿,谢谢。事后看来,其中一件非常明显的事情。 ;)
  • 这是否适用于更现代的版本。我们有 2020 年的解决方案吗?

标签: javascript mongodb


【解决方案1】:

Mongo 4.2开始,db.collection.update()可以接受一个聚合管道,最后允许根据自己的值更新一个字段;从而避免低效的 find/foreach 模式。

此外,您正在查看 $inc 运算符来添加一天,但现在我们可以使用聚合管道作为更新,可以使用 $add 运算符:

// { "date" : ISODate("2020-04-05T07:14:17.802Z"), "x" : "y" }
db.collection.updateMany(
  { date : { $exists : true } },
  [{ $set: { date: { $add: ["$date", 24*60*60000] } } }]
)
// { "date" : ISODate("2020-04-06T07:14:17.802Z"), "x" : "y" }
  • 第一部分{ date : { $exists : true } } 是匹配查询,过滤要更新的文档(在我们的例子中是所有具有date 字段的文档)。

  • 第二部分[{ $set: { date: { $add: ["$date", 24*60*60000] } } }] 是更新聚合管道(注意方括号表示使用聚合管道)。 $set 是一个新的聚合运算符,别名为$addFields。然后可以在$set 阶段内使用任何聚合运算符;在我们的例子中,一个简单的$addition 介于现有日期和以毫秒为单位的一天的表示之间。

【讨论】:

    【解决方案2】:

    问题是我的$exists 查询(显然,在第二次查看时)在错误的位置。返回的文件肯定不包括my_date

    这是修补后的功能,按预期工作。

    var incrementDates = function() {
      db.blah.find({ ... , my_date : { $exists : true } ).forEach(function(doc) {
        db.blah.update(
           { _id     : doc._id }
         , { $set : { my_date : new Date(doc.my_date.getTime() + 86400000) }}
        );
      });
    }
    

    【讨论】:

      【解决方案3】:

      Mongo 5.0 开始,这是新的$dateAdd 聚合运算符的一个很好的用例:

      // { "date" : ISODate("2020-04-05T07:14:17.802Z"), "x" : "y" }
      db.collection.updateMany(
        { date : { $exists : true } },
        [{ $set: { date: { $dateAdd: { startDate: "$date", unit: "day", amount: 1 } } } }]
      )
      // { "date" : ISODate("2020-04-06T07:14:17.802Z"), "x" : "y" }
      
      • 第一部分{ date : { $exists : true } } 是匹配查询,过滤要更新的文档(在我们的例子中是所有具有date 字段的文档)。

      • 第二部分[{ $set: { date: { $dateAdd: { startDate: "$date", unit: "day", amount: 1 } } } }],更新date字段的值,将($dateAdd)1(amount)day(unit)添加到$date(startDate) )。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-05-03
        • 1970-01-01
        • 2018-12-08
        • 2019-03-12
        相关资源
        最近更新 更多