CreatedAt and documents

I’m working through the Meteor tutorial and noticed that one of the fields for Tasks.insert is createdAt: new Date()

In Rails, the created_at property is automatically added. Is there a package that would automatically do this? It looks like I could write my own collection hooks, but I’m wondering if there is a standard package people use.

Also, suppose I didn’t use a hook for this, and left it as Tasks.insert({…}) Since this is evaluated client-side, if someone’s browser were to have a different time (say, it’s set incorrectly or whatever), would it use the wrong time?

1 Like

Look at this package.

1 Like

The way I see most people doing it is to use methods for all database access. You’d simply build up the object on the server and then do Tasks.insert(). Since you’d want to do validation on the server anyway I really don’t see why you’d go through the trouble of setting up allow/deny instead of letting the server handle it. This does not affect latency compensation!

Use the collection hooks package

Projects.before.insert(function (userId, doc) {

  if(Meteor.isServer) {
    //Format the document
    doc.createdAt = Date.now();
    doc.updatedAt = Date.now();
}
});

Alright, thanks, this looks good: https://atmospherejs.com/zimme/collection-timestampable

2 Likes

I don’t understand. If you call it from the server, you have latency.
At the moment I’m using a server side method t in this way on slow lines I have a delay between typing a new message e showing it on a channel ─ I’m working on multi channel chat. On the other hand I need to get the time stamp from the server in order to show chat messages in the correct order.

A I missing anything here?

I have the same need. Does that package manage the time stamp server side?
I need something to make a client side insert of a record without specifying the createdAt field and I’d like to get the server complete that record adding the time stamp. Is it that what collection timestampable actually does?

Thanks

My fault. I tested the collection-timestampable package and it actually set the time stamp at the server, but doing this way I got a flickering on the screen on slow lines. This is because the message is temporarily showed at the top of the list - having no creation date - and then moved at the bottom. So, for my case, the only way seems to be running the insert as a server method.

Why don’t you use the usual Meteor pattern: inserting from both client and server? This way you immediately get a value on client, until it is updated by the server with the right timestamp.
You can compute your temporary client-side timestamp the way you want, for example by taking a date far away in the future (quick and dirty) or by approximating the server time in a more sophisticated way (see this package).

What do you mean exactly?
If I use Messages.insert(...) setting the createdAt field directly from the template I have a problem for users on different time zones. If I use Meteor.call(…) letting the server do the insert I have latency on message display.

I don’t know any other pattern. Can you elaborate, please?

When you define a method on both client and server, any insert operation will insert both on client (in the local minimongo cache) and server. Then, if there is any discrepancy between client data and server data, the client data will be updated with the right (server) data.

So the simplest way is:

// Client/server method
Meteor.methods({
  newDoc: function() {
    return MyCollection.insert({
      someData: someData,
      createdAt: new Date()
    });
  }
});

In that case, client side, createdAt will temporarily be the client date, until it is updated with the server date.

Depending on your need, momentarily having a wrong client-side date might be ok, for example if it is only to display a sorted list in the right order.

But then you can tune this in many ways:

// Client/server method
Meteor.methods({
  newDoc: function() {
    var createdAt = Meteor.isServer 
      ? (new Date()) 
      : (whatever computation, including estimating server time, etc.);
    return MyCollection.insert({
      someData: someData,
      createdAt: createdAt
    });
  }
});
1 Like

@Steve thanks for your thorough answer. Now latency compensation is fully understood. Reading Meteor documentation I completely misunderstood this point.
My list is sorted by creation date and the package you mentioned mizzao:meteor-timesync looks awesome for my needs.
Because of I separate posts on the list by day of posting I need to be as more accurate as possible.

[UPDATE]
This pattern suggested on stackoverflow looks very interesting too:

lib/method.js

Meteor.method({
  method: function(args){
    check(args, [...]);
    //
    return implementation(args);
  }
});

The trick is to define the implementation separately on client and server, depending on the context, the correct function will get called.

client/method.js

implementation = function(args){
  // define your client simulation / stub
};

server/method.js

implementation = function(args){
  // define your server implementation
};

Notice that you can do this as well:

client/method.js

Meteor.methods({
  myMethod: function(){
    // Client-side implementation of myMethod
    ...
  }
});

server/method.js

Meteor.methods({
  myMethod: function(){
    // Server-side implementation of myMethod
    ...
  }
});

Much as I try to avoid Meteor.isClient and Meteor.isServer, they do have their place. Having physically separate (in different files) client and server versions of a method does introduce a risk of changing one and forgetting about the other.

Better (in my opinion) is to put the functionality in one, shared file (for example in lib/) and using Meteor.isClient/Meteor.isServer at appropriate places to tailor behaviour. Alternatively, you can also use this.isSimulation in a method - docs, which identifies whether you are in a stub (clientside method). See the description of stubs in the method docs.

1 Like

@robfallows, agreed.

Just curious: did you understand the practical difference between isClient and isSimulation?

And there is 1 secret - automatically created _id contains CreatedAt timestamp with 1s precision.
See mongo ObjectID docs.
Have fun

I use this as a general reference.

In the context of the original requirement either would work, but isClient is “safer”.

1 Like