如何在MongoDB中正确地增加多个日期?

16

作为一个不是特别擅长Javascript的人,我试图更新Mongo中很多Date对象时遇到了一些麻烦。

看起来$inc对于Date对象尚未实现。所以,为了尝试将一堆日期向后推一天,我通过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存在的文档。

对于这里正在发生什么,有什么想法吗?更重要的是:有没有更好的方法来做到这一点?


1
故障排除建议:在执行db.blah.update之前,您是否尝试过输出doc.my_date?这可以告诉您它无法处理的my_date的值。 - Philipp
@Philipp 嘿,谢谢。这是一件事情,在事后看来非常明显。;) - jtobin
这是否适用于更现代的版本?我们有没有2020年的解决方案? - Mark Odey
3个回答

15

Mongo 4.2 开始,db.collection.update() 可以接受聚合管道,最终允许基于其自身值更新字段,从而避免了低效的查找/循环模式。

此外,您之前考虑使用 $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 阶段中使用任何聚合运算符;在我们的情况下,是将现有日期和一天的毫秒表示相加的简单$add 运算。


13
问题在于我的 $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) }}
    );
  });
}

5

从开始,$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 } } } }],通过添加($dateAdd)一(amount)天(unit)到$date(startDate),来更新date字段的值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接