Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
168 views
in Technique[技术] by (71.8m points)

javascript - How does one properly increment many dates in mongoDB?

Not being a particularly strong Javascript guy, I'm having a bit of trouble trying to update a lot of Date objects in Mongo.

It seems that $inc has not yet been implemented for Date objects. So, to try and bump a bunch of dates by a day, I called (something like) this script from bash via mongo myScript.js:

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

The basic idea seems to work well enough in the 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")

But not so well in the script:

TypeError: doc.my_date has no properties

So I take it that I'm trying to call getTime on a null somewhere, even though the query in my update should only return documents where my_date exists.

Any ideas as to what's happening here? More importantly: is there a better way to do this?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Starting in Mongo 4.2, db.collection.update() can accept an aggregation pipeline, finally allowing the update of a field based on its own value; thus avoiding inefficient find/foreach patterns.

Also, you were looking at the $inc operator to add a day, but now that we can use an aggregation pipeline as an update, the $add operator can be used:

// { "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" }
  • The first part { date : { $exists : true } } is the match query, filtering which documents to update (in our case all documents having the date field).

  • The second part [{ $set: { date: { $add: ["$date", 24*60*60000] } } }] is the update aggregation pipeline (note the squared brackets signifying the use of an aggregation pipeline). $set is a new aggregation operator and an alias of $addFields. Then any aggregation operator can be used within the $set stage; in our case a simple $addition between the existing date and the representation of a day in milliseconds.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...