How do I define a model for which created_at and updated_at are provided rather than generated?
I'm importing data from somewhere that already has data for created_at and updated_at fields that I would like to preserve rather than generating whenever the object is created/updated by sequelize (our secondary store).
I've tried every likely permutation of model definition and options to get this to work and still sequelize overwrites my fields with it's own timestamps: {silent: true}, etc...
To be clear, the input data has createdAt and updatedAt and I'd like to use sequelize's bulkCreate(), etc such that input values provided are used and stored on the model as created_at and updated_at rather than generated by sequelize.
This is my current model definition:
const Lead = sequelize.define('lead', {
objectId: {
type: Sequelize.STRING,
field: 'objectId',
primaryKey: true,
allowNull: false
},
firstName: {
type: Sequelize.STRING,
field: 'first_name'
},
lastName: {
type: Sequelize.STRING,
field: 'last_name'
},
phoneNumber: {
type: Sequelize.STRING,
field: 'phone_number'
},
createdAt: {
type: Sequelize.DATE,
field: 'created_at',
},
updatedAt: {
type: Sequelize.DATE,
field: 'updated_at'
}
}, {
freezeTableName: true, // Model tableName will be the same as the model name
timestamps: false,
underscored: true
});
The option is
timestamps: false,
Where timestamps is written fully lowercase
Update:
From looking at the code of the bulkCreate() function, it looks that it always updates the timestamps, so, without a patch this is not possible right now
Related
I want to translate this psql table creation query to sequelize:
PSQL:
CREATE TABLE categories
(
id INTEGER NOT NULL PRIMARY KEY,
name CHARACTER VARYING(50) NOT NULL UNIQUE,
description CHARACTER VARYING(100) NOT NULL
);
CREATE TABLE posts
(
id INTEGER NOT NULL PRIMARY KEY,
title CHARACTER VARYING(50) NOT NULL,
content CHARACTER VARYING(100) NOT NULL,
from_category CHARACTER VARYING(50) NOT NULL,
CONSTRAINT fk_from_category
FOREIGN KEY(from_category)
REFERENCES categories(name)
)
Its a simple fk association, with varchar type.
I have read sequelize docs, but i still don't know how to change the relation from primary keys to varchar.
From what i read, this is what you can do with associations:
Post.belongsTo(Category, {
foreignKey: {
onDelete: ...,
onUpdate: ...,
validate: {...},
},
});
and thats all i could find about on youtube too..
I would be really happy if you can help me. I have spent too much time on this already, but i want it to work!
Follow this example using belongsTo:
class Category extends Model { }
Category.init({
id: {
type: DataTypes.INTEGER,
primaryKey: true
},
name: {
type: DataTypes.STRING,
unique: true,
allowNull: false
},
description: {
type: DataTypes.STRING,
allowNull: false
}
}, { sequelize, modelName: 'categories' });
class Post extends Model { }
Post.init({
id: {
type: DataTypes.INTEGER,
primaryKey: true
},
title: {
type: DataTypes.STRING,
allowNull: false
},
content: {
type: DataTypes.STRING,
allowNull: false
},
from_category: {
type: DataTypes.STRING,
allowNull: false
}
}, { sequelize, modelName: 'posts' });
Post.belongsTo(Category, {
foreignKey: 'from_category',
targetKey: 'name'
});
Read more about to understand with more details in the official docs.
I got some trouble understanding how associations works with Sequelize. I am working on a project which have almost the same features that Reddit and therefore I am trying to associate the User table to the Post table as a 1:N associations.
User Model:
const { Sequelize, Model, DataTypes } = require ('sequelize');
const db = require('../config/db');
const Post = require('./Post')
class User extends Model{}
User.init({
id: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true,
},
username:{
type: DataTypes.STRING,
unique: true
},
email:{
type: DataTypes.STRING
},
password:{
type: DataTypes.STRING
},
isAdmin:{
type: DataTypes.BOOLEAN,
defaultValue: false
}
}, {sequelize: db, modelName:'User'}
);
User.hasMany(Post,{as: 'posts', foreignKey: 'id'});
User.sync();
module.exports = User;
Post Model:
const { Sequelize, Model, DataTypes } = require ('sequelize');
const db = require('../config/db');
const User = require('./User');
class Post extends Model{}
Post.init({
id: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true,
},
text:{
type: Sequelize.STRING
},
image:{
type: Sequelize.STRING
},
likes:{
type: Sequelize.INTEGER,
}
}, {sequelize: db, modelName:'Post'}
)
Post.sync();
module.exports = Post;
When I launch my app, I can see that it mention that post have the foreign key id but still I don't have hany column that link User to Post in my DB. What I am missing?
Executing (default): CREATE TABLE IF NOT EXISTS `Posts` (`id` INTEGER NOT NULL auto_increment , `text` VARCHAR(255), `image` VARCHAR(255), `likes` INTEGER, `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMARY KEY (`id`), **FOREIGN KEY (`id`)** REFERENCES `Users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE) ENGINE=InnoDB;
First, you need to indicate the correct value in the foreignKey option, it should be a field like user_id in Post model:
User.hasMany(Post,{as: 'posts', foreignKey: 'user_id'});
Second, you need to move association definitons and sync calls (and cross-refrences of models) from model modules outside. You need to register all models and only after that to define all their associations and the last action would be calling sync methods.
See the question and my answer here to get an idea how to do it.
I have been working on my models for my ERD in node / postgres / sequelize and have been loosely defining my associations as I have been going along. In the case of the below am I correct in believing that I only have to define the foreign keys on the one table? In the example below I have two fields that I want to pull the associated data from other tables when I query them. Am I going about this the right way.
I have previously defined foreign keys in PhpMyAdmin and only done them on the one table. I have yet to pull the correct data in my Postman queries and have only returned the int values of the primary table. Is this dependent on me having my foreign keys set-up correctly? Or do I need to specify something in my controller API?
articleID: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false
},
articleTitle: {
type: Sequelize.TEXT
},
articleContent: {
type: Sequelize.TEXT
},
articlePhotos: {
data: Sequelize.Buffer,
type: Sequelize.TEXT
},
articleAuthor: {
type: Sequelize.INTEGER
},
articleType: {
type: Sequelize.INTEGER
}},
{
timestamps: false
}, {});
article.associate = function(models){
article.articleType.belongsTo(models.article, {
foreignKey: {name: 'articleTypeID', as: 'articleType'}})
article.articleAuthor.belongsTo(models.userLogin, {
foreignKey: {name: 'userID', as: 'userAuthor'}})
};
I'm working on a create method for an association between two classes. The sequelize documentation indicates that this can be done in one step using includes
IntramuralAthlete.create(intramuralAthlete,{
include: [Person]
}).then((data,err)=>{
if(data)res.json(data);
else res.status(422).json(err);
}).catch(function(error) {
res.status(422).json({message: "failed to create athlete", error: error.message});
});
My model association looks like this
var Person = require('../models').person;
var IntramuralAthlete = require('../models').intramuralAthlete;
IntramuralAthlete.belongsTo(Person);
And the value of intramural athlete when I log it is
{
person:
{ firstName: 'Test',
lastName: 'User',
email: 'test#user.com'
},
grade: '12th',
organizationId: 1
}
But I get the error notNull Violation: personId cannot be null. This error makes it sound like something is wrong with the way I'm indicating to Sequelize that I'm intending to create the personId in that same call.
Is there something wrong in the way I indicate to the create statement what associated tables to create with the IntramuralAthlete?
Thanks!
EDIT:
I have also tried with the following structure with the same result
{
Person: {
firstName: 'Test',
lastName: 'User',
email: 'test#user.com'
},
grade: '12th',
organizationId: 1
}
My model is as follows:
module.exports = function(sequelize, DataTypes) {
return sequelize.define('intramuralAthlete', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true
},
createdAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: sequelize.literal('CURRENT_TIMESTAMP')
},
updatedAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: sequelize.literal('CURRENT_TIMESTAMP')
},
grade: {
type: DataTypes.STRING,
allowNull: true
},
age: {
type: DataTypes.INTEGER(11),
allowNull: true
},
school: {
type: DataTypes.STRING,
allowNull: true
},
notes: {
type: DataTypes.STRING,
allowNull: true
},
guardianId: {
type: DataTypes.INTEGER(11),
allowNull: true,
references: {
model: 'contact',
key: 'id'
}
},
personId: {
type: DataTypes.INTEGER(11),
allowNull: false,
references: {
model: 'person',
key: 'id'
}
},
mobileAthleteId: {
type: DataTypes.INTEGER(11),
allowNull: true,
references: {
model: 'mobileAthlete',
key: 'id'
}
},
organizationId: {
type: DataTypes.INTEGER(11),
allowNull: false,
references: {
model: 'organization',
key: 'id'
}
}
}, {
tableName: 'intramuralAthlete'
});
};
I suppose that your models are named Person and IntramuralAthlete (first arguments of sequelize.define method). In this case, when you create an association like yours, and do not define the as attribute, your create data object should look as follows
{
Person: {
firstName: 'Test',
lastName: 'User',
email: 'test#user.com'
},
grade: '12th',
organizationId: 1
}
If you want to use person instead (just as in your code), you should define the association a little bit differently
IntramuralAthlete.belongsTo(Person, { as: 'person' });
Then, you would have to perform some changes in the create query in the include attribute of the options like this
IntramuralAthlete.create(data, {
include: [
{ model: Person, as: 'person' }
]
}).then((result) => {
// both instances should be created now
});
EDIT: Trick the save() method with empty value of personId
You can maintain the allowNull: false if you do something like that
{
person: {
// person data
},
personId: '', // whatever value - empty string, empty object etc.
grade: '12th',
organizationId: 1
}
EDIT 2: Disable validation when creating.
This case assumes that the validation is turned off. It seems like a bad idea to omit model validation, however there still maintains the database table level validation - defined in migrations, where it can still check if personId value was set
IntramuralAthlete.create(data, {
include: [
{ model: Person, as: 'person' }
],
validate: false
}).then((result) => {
// both instances should be created now
});
In this case the data object can be as in your example - without the personId attribute. We omit the model level validation which allows to pass null value, however if during the save() method it would still be null value - database level validation would throw an error.
first of all, when you associatea a model with belongsTo, sequelize will add automatically the target model primary key as a foreign key in the source model. in most of cases you don't need to define it by yourself, so in your case when you define IntramuralAthlete.belongsTo(Person) sequelize adds PersonId as a foreign key in IntramuralAthlete. your IntramuralAthlete model should looks like:
module.exports = function(sequelize, DataTypes) {
return sequelize.define('intramuralAthlete', {
grade: {
type: DataTypes.STRING,
allowNull: true
},
age: {
type: DataTypes.INTEGER(11),
allowNull: true
},
school: {
type: DataTypes.STRING,
allowNull: true
},
notes: {
type: DataTypes.STRING,
allowNull: true
}
});
};
now you can create an intramuralAthlete like your code above. for example:
let data = {
Person: {
firstName: 'Test',
lastName: 'User',
email: 'test#user.com'
},
grade: '12th',
notes: 'test notes'
}
IntramuralAthlete.create(data, {include: [Person]}).then((result) => {
// both instances should be created now
});
be carefull with the model name.
second I suppose that your IntramuralAthlete model has more than one belongsTo association. just you need to define them as the previous one association and sequelize will add their primary keys as foreign keys in the IntramuralAthlete model.
third, when you define a model, sequelize adds automatically an id datafield as a primary key and autoincrement and also adds createdAt and updatedAt datafields with a default CURRENT_TIMESTAMP value, so you don't need to define them in your model
I'm using Sequelize v3.5.1 with PostgreSQL v9.4.4 on a NodeJS server project.
In the model definition, it's not entirely clear to me what are the effects of adding the option unique: true to a property.
Let's take this code for example:
sequelize.define('User', {
email: {
type: Sequelize.STRING,
unique: true
},
password: {
type: Sequelize.STRING,
allowNull: false
}
});
Does this mean that PostgreSQL will build a unique index on email? So, is it just a shorthand method for this?
sequelize.define('User', {
email: {
type: Sequelize.STRING,
},
password: {
type: Sequelize.STRING,
allowNull: false
}
}, {
indexes: [
{
unique: true,
fields: ['email']
}
]
});
If so, will such index speed up table queries for email, or just ensure uniqueness?
Thanks!
A unique index will do both, it will speed up queries (as it has to create an index), and it will ensure that every value is unique.