Sequalize TimeStamps - node.js

I was facing a problem with TimeStamps, In my model I've specified like
{
timestamps: true,
createdAt: 'createdOn',
updatedAt: 'updatedOn',
tableName: 'Employee'
});
But in database both createdOn and updatedOn were storing date values, I want updatedOn as null because it was creating newly. Am I missing anything,Thanks in Advance.

Unless you disable it, updatedAt and createdAt are provided by Sequelize without having to manually add them. - http://docs.sequelizejs.com/en/v3/docs/models-definition/#configuration
Creating a new row is considered an update and so yes, updatedAt and CreatedAt will both have the same timestamp on first write. If you really want to track whether or not something is new you might look into using a "status" column with an ENUM (for multiple status values) or a BOOLEAN to represent either new or not - http://docs.sequelizejs.com/en/v3/docs/models-definition/#data-types

Related

Does Mongoose upsert operation update/renew default schema values?

Mongoose Schema:
new Schema({
...
createDate: { type: Date, default: Date.now },
updateDate: { type: Date, default: Date.now }
});
Upsert operation:
const upsertDoc = {
...
}
Model.update({ key: 123 }, upsertDoc, { upsert: true })
when I upsert with update or findOneAndUpdate the default schema values createDate and updateDate are always renewed no matter document is inserted or updated. It's same when I use $set (in which of course I don't pass dates).
I don't seem to find anything to tell if it's an expected behavior. I expect dates to be added only on insert and not update, unless explicitly set.
If you are looking for "proof" of the expected behavior, then look no further than the source code itself. Particularly within the schema.js main definition:
updates.$setOnInsert = {};
updates.$setOnInsert[createdAt] = now;
}
return updates;
};
this.methods.initializeTimestamps = function() {
if (createdAt && !this.get(createdAt)) {
this.set(createdAt, new Date());
}
if (updatedAt && !this.get(updatedAt)) {
this.set(updatedAt, new Date());
}
return this;
};
this.pre('findOneAndUpdate', _setTimestampsOnUpdate);
this.pre('update', _setTimestampsOnUpdate);
this.pre('updateOne', _setTimestampsOnUpdate);
this.pre('updateMany', _setTimestampsOnUpdate);
}
function _setTimestampsOnUpdate(next) {
var overwrite = this.options.overwrite;
this.update({}, genUpdates(this.getUpdate(), overwrite), {
overwrite: overwrite
});
applyTimestampsToChildren(this);
next();
}
So there you can see all the 'pre' middleware handlers being registered for each of the "update" method variants and to the same functional code. These all essentially modify the $set operator in any "update" you issue to include the updatedAt field, or whatever name you mapped to that key in the schema options.
The actual statement sent with "upsert" actions uses $setOnInsert for the createdAt field or mapped option name ( see the top of the listing ). This action only applies when an "upsert" actually occurs, so documents that exist and are merely matches for any of the "update" methods are never actually touched by this value.
Those operators are part of how MongoDB works and not really to do with mongoose, but the code shown here shows how mongoose "adjusts" your "update" actions in order to include these additional operations.
For reference the whole main function in schema.js which works out what to apply currently begins at Line #798 for the genUpdates() function as called in the bottom part of the listing shown here yet the top part is the last few lines of that function where the keys of $setOnInsert get defined.
So in summary, YES every "update" action is intentional that the updatedAt mapped field has the current Date value assigned, and also that the "updates" are modified to include the $setOnInsert action which only applies when a new document is created as the result of an "upsert" action for the createdAt mapped field.
Well, I'd always recommend to use the provided and recommended way to manage createdAt and updatedAt by mongoose. Simply by passing timeStamp: true as schema options.
This is always a best practice and lets you not to be worried about such behaviors.
I use it and I never see a problem with timestamps using update or findOneAndUpdate.
Here is how you use it
new Schema({
... //Your schema
},{ timestamps: true})

Passing current time to Mongoose query

I've run into problem. I made field in my Mongoose schema with type "Date":
...
timeOfPassingQuestion: Date,
...
Now, I want to pass current time in hours, minutes, seconds and miliseconds and save it into that field. How should I format my Node variable so I can pass it without errors?
Edit: Also, I forgot to say that I wanna later see how much time user spent answering question by subtracting current time and time that I pulled from DB, timeOfPassingQuestion field.
This is the syntax to create a schema that supports a date field:
// Schema
{ //...
someDate: Date,
}
// date object that you can use whenever you decide to set it
var dateObj = new Date();
This will create a JavaScript date object that you can then pass into your Mongoose object for the date field.
Or, if you will always want it on creation, put it directly in your mongoose schema
{ //...
createdDate: { type: Date, default: Date.now },
}
In order to compare the time in the future, I suggest you use moment.js, then you can query the time difference like so:
moment(Model.createdDate).fromNow();
Sources:
Mongoose Schema
Moment.js fromNow

sequelize - update row without altering the updated_at field

I am using sequelize.js library as ORM in node development. When update a row using sequelize, 'updated_at' field changed to current time-stamp. I would like to know how can I prevent this ? Without changing 'updated_at' field I would like to update other fields using sequlize API, not running raw query.
According to http://docs.sequelizejs.com/class/lib/model.js~Model.html#static-method-update you can use the "silent" option to run an update query but not update the updateAt field.
options.silent Boolean
optional
default: false
If true, the updatedAt timestamp will not be updated.
myModelInstance.update(values, {
silent: true
})
In your model definition, you can turn timestamps off for specific fields.
If you want sequelize to handle timestamps, but only want some of them, or want your timestamps to be called something else, you can override each column individually:
var Foo = sequelize.define('foo', { /* bla */ }, {
// don't forget to enable timestamps!
timestamps: true,
// I don't want createdAt
createdAt: false,
// I want updatedAt to actually be called updateTimestamp
updatedAt: 'updateTimestamp'
// And deletedAt to be called destroyTime (remember to enable paranoid for this to work)
deletedAt: 'destroyTime',
paranoid: true
});
Otherwise, you can turn timestamps off and handle them manually per-update as you want to.

how to update the field 'updated_at' of a sequelize model without modifiyng any attributes

I'm using sequelize 2.0.0 with PostgreSQL.
I would like to know if it's possible to update the field 'updated_at' of a model with one method. If yes, how can I achieve that?
For instance, in others frameworks, like Laravel, you have model.touch() to automatically update the 'updated_at' of a model.
I've already tried to use model.save() but as the sequelize doc says, calling this method without attributes does nothing. Also, in the doc, I didn't find anything that allow me to do what I need to do simply.
Thanks in advance for help.
Edit:
To give an example of what I'm trying to achieved, I've already had an instance of my model:
Model.findById(1).then(function(myInstance){
[...]
myInstance.update() //here, I didn't change any attributes of myInstance and I would like to update the field udpated_at without doing another query.
[...]
}):
The question is : How can I update the field updated_at of my previous instance with one method?
To update an instance value, you can use instance.set(key, value, [options]).
myInstance.set('updatedAt', new Date());
myInstance.save().then(function() {
// my nice callback stuff
});
The sequelize docs have a good example of doing an update query if you don't have an instance:
Post.update({
updatedAt: null,
}, {
where: {
deletedAt: {
$ne: null
}
}
});
My solution is a little hackey. I had to update a field on the instance to be different than what it was supposed to be, so that sequelize thought that the field changed, even if it didn't; and make sure the proper field data was passed in afterwards.
For example, let's say the variable myInstance has a field named title, and a variable data holds the unchanged (or new) title ( {title:"OLD_OR_NEW_TITLE"} ). If I add to the code myInstance.set('title', data.title+'_FAKE'), then when the update/save method is called ( myInstance.update(data) ), sequelize will think that the field has changed, even though it might not have.

Default values using Mongoose & MongoDB

In my original schema I had a field :
created: Date
I added a default to this field like so :
created: { type: Date, default: Date.now }
Problem now is that some pre-existing records don't have this field, when these records are fetched the current date time is set for this field in the projected data.
Ideally is it possible, where the record doesn't have the field, to exclude it from the projected data automatically, as it was before adding the schema default?
Failing that, how would I set up an override for the insert operation to set the defaults there instead?

Resources