Sequelize automatically adds colums - node.js

[Model].findOne({}) throws unknown colum error, but i dont have that column in my model, but it adds the colum modifieddate and updatedat and somecolum while fineOne runs

You have to add timestamp:false in the options where you are defining the model.
For example:
var Bar = sequelize.define('Bar', { }, {
timestamps: false,
})
For reference check this Sequelize model definition

Related

Sequelize Error : Column names in each table must be unique

I had an error in Sequelize with a foreign key not matching a column name. Checking the db, I saw that the column 'WokflowId' was named 'WorkflowID', so I changed the name in the Sequelize model.
It look like this
'use strict';
const Sequelize = require('sequelize');
const sequelize = require('../util/database');
const WorkflowsAccessRights = sequelize.define('Workflows_AccessRights', {
id:{
type: Sequelize.BIGINT,
autoIncrement: true,
allowNull: false,
primaryKey: true
},
WorkflowID: Sequelize.BIGINT,
GroupID: Sequelize.BIGINT,
Enabled: Sequelize.INTEGER
},{
timestamps: false,
freezeTableName: true,
});
module.exports = WorkflowsAccessRights
But now that I changed the column name to get the right one, I get this error
Column names in each table must be unique. Column name 'WorkflowId' in table 'Workflows_AccessRights' is specified more than once.
Except that no column has this name now... Did I miss something in the setup or is there a way to freeze the column name?
Hope the following link will be helpful for you. It asks to put IF NOT EXISTS to the SQL script as follows,
IF NOT EXISTS(SELECT * FROM sys.columns WHERE Name = 'ColumnName'
AND object_id = OBJECT_ID('YourTableName'))
BEGIN
ALTER TABLE dbo.YourTableName
ADD ColumnName INT -- or whatever it is
END
Check this link. It is the same question that you have asked
So, after searching in the whole project. I found out that I was calling a foreignKey on WorkflowId. Therefore Sequelize tried to create a new column called WorkfklowId and had a bug doing it. I just renamed the foreignKey and it worked.

Sequelize: Can't do update on column UpdatedAt

I've an express apps that use Sequelize as ORM. Basically, columns createdAt and updatedAt auto-generated by Sequelize.
Every time I do update data in a row except column updatedAt, the column updatedAt will be updated based on current datetime.
But when I'm trying to update the column updatedAt, it didn't update the value of column updatedAt.
I've several way based on docs and another issue in so, like:
value.set('createdAt', new Date());
value.save().then(value1 => {
console.log('UpdatedAt has been updated');
next();
}
)
and
Token.update(
{
updatedAt: new Date
},
{
where: {
token_id: token
}
}
).then(value1 => {
console.log('Token UpdatedAt has been updated');
}
)
But non of both work.
Anyone know why? and how to fix that. Thankyou.
The short and simple way for this is :
Token.changed('updatedAt', true); // <--- This will update the updatedAt field

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})

Mongoose schema transform field before returning the record

Is it possible to add a default value if the field is empty/not present in the record?
ex:
if ( ! record.options ) { record.options = {}; }
After searching a lot, the response i found was i can do this using .toObject() or .toJSON(), But i am not calling any of these and i just want to add this conditions on the schema so it works directly.
Right now i am checking for this condition in the returned record/(s) which is bad as i am repeating the same logic for .find and .findOne
If you want to add empty default value, you need to do something like this:
var schema = new Schema({
info: { type: <YOUR_TYPE_HERE>, default: {} }
}, { minimize: false });

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.

Resources