Insert field with $currentDate to MongoDB collection in Meteor
Asked Answered
G

5

32

Not sure how to use $currentDate when inserting a document into a MongoDB collection in Meteor.

Can this only be used in an update, not an insert? Would seem strange, but I don't see an alternative (other than using new Date instead).

Example

Stuff.insert({ 
   owner: Meteor.userId(),
   createdAt: ..., // how to create this field with $currentDate ?
   theStuff: "Some of the good stuff"
})

Notes / Thoughts / TL,DR

  • Fields can't start with $ operators or, as far as I know, curly braces {}.
  • What's the point of having an operator that only works with updates, if that's indeed the case?
  • Why/when is $currentDate better than new Date?
  • One nice thing, if using Moment.js esp, is that $currentDate is entered in ISO 8601 format.
  • Is the answer to do some kind of upsert from the start? If so, could this have unintended consequences?
Gaza answered 13/5, 2015 at 2:31 Comment(0)
A
39

What's the point of having an operator that only works with updates, if that's indeed the case?

$currentDate is an update operator thus you can't use it with the collection.insert method. But when upsert is true it will create a new document when no document matches the query criteria. MongoDB operators tend to follow the Unix philosophy

Do One Thing and Do It Well

So each operator should perform only one task.

Why/when is $currentDate better than new Date?

First I would like to mention that new Date is a JavaScript Date instance.

$currentDate and new Date can be used when you want to update the value of a field to current date but with new Date you need to use another update operator for it to work. For example:

  • Using new Date

    db.collection.update({ "name": "bar" }, { "$set": { "date": new Date() }})
    
  • Using $currentDate

    db.collection.update({ "name": "bar"}, 
        { "$currentDate": { "date": { "$type": date }}}
    )
    

Unlike $currentDate, new Date can be use with the insert method and value can be set to a particular if Date is call with more than on argument.

Amelina answered 13/5, 2015 at 4:27 Comment(5)
Still. If you have a distributed application connecting to your replicaSet / sharded cluster inserting a lot of docs per second you would like a createdAt field to be consistent and using the $currentDate on the Insert would be a better solution. If you don't have a high insertion volume upsert and insert might be the same for you but they are actually not. Upsert is slower and when you use new Date you are getting the date from the client machine not from the database server, thus you are vulnerable to inconsistencies when it comes to sorting by createdAt.Hessite
@MestreSan $currentDate only works with updateOne or updateMany. Not with insert. Perhaps you mean update when you say insert in comment.Amelina
No @user3100115, I know that $currentDate only woks with updates and not with insert. What I meant was that would be a good feature to have the $currentDate operator available on inserts. Just like any RDMS has the now function available on inserts for example for one to use on a field createdAt to know the precise moment your record was created.Hessite
@MestreSan Checkout my answer to this question, it may be a solution for what you're stating: https://mcmap.net/q/454922/-is-there-any-equivalent-of-now-in-mongodbBoeschen
Is it possible to use $currentDate in conjunction with the $setOnInsert operator. This would allow an upsert\insert to set a "created" date, without upsert\update overwriting it each time.Burgess
S
6

You can retrieve timestamp from autogenerated "_id" that is created within insert operation.

http://api.mongodb.com/java/current/org/bson/types/ObjectId.html

Just use the method : ObjectId.getTimestamp().

Timestamp granularity is in seconds.

Spontaneous answered 17/9, 2017 at 17:49 Comment(0)
D
1

It will become more simple if you will use autoValue in collection model

createdAt:
type: Date
autoValue: ->
  if this.isInsert
    return new Date
  else if this.isUpsert
    return $setOnInsert: new Date
  else
    this.unset()

It will automatically set date while insert or update the data into it

Dinnie answered 19/9, 2017 at 4:56 Comment(0)
E
1

$currentDate when used in the $update construct can be used to insert fields if they do not pre-exist in the document.

Quoting documentation for Mongodb 3.4: Behavior

If the field does not exist, $currentDate adds the field to a document.
Evenings answered 26/4, 2018 at 7:26 Comment(0)
T
0

Although I do totally appreciate that this design makes perfect sense, there is an argument, perhaps a bad one, that you want to set the updated_at field to something sensible when you insert a document. One reason that you might want to do this is to avoid always needing to query on two fields to get the last updated time. Like I say, this might be bad juju, but well there you go.

Anyway the best hack that I could come up with to do this is to perform an upsert that filters on not the empty filter. That guarantees that the upsert is always an insert.

Just a small comment on this to the MongoDB Devs. As someone who has been working with databases for more years than they care to remember, getting my head around how one is supposed to do timestamps correctly in MongoDB:

created_at => _id.Timestamp
updated_at => $currentDate()

has taken me far too long. Maybe that's my fault, it probably is, but it's something that I think most people probably want / need to do and as a concept it could be explained better. If you search around you will find a lot of bad / wrong information, because I'm pretty sure that this is the way to do it and ... well the internet is far from at consensus on this (although I am now).

I don't know, maybe it's a test. Maybe this is the first thing you ask someone when you are hiring a MongoDB developer: how do you do timestamps? Well, that's what I'd ask anyway because if you know you've probably learned most of the API by that stage.

Thagard answered 28/9, 2021 at 14:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.