I found out that sequelize is creating tables automatically according to the definition of my model names.
I have the following code:
const DataTypes = require("sequelize");
const sequelize = require("../mysql.js");
const Approver = sequelize.define("approver", {
subordinate_id: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: "user",
key: "id",
},
},
leader_id: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: "user",
key: "id",
},
},
main_leader_id: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: "user",
key: "id",
},
},
});
const connect = async () => {
await Approver.sync();
};
connect();
module.exports = Approver;
every time I run the local server, I get the following message in the terminal:
CREATE TABLE IF NOT EXISTS `approvers` (`id` INTEGER NOT NULL auto_increment , `subordinate_id` INTEGER NOT NULL, `leader_id` INTEGER NOT NULL, `main_leader_id` INTEGER NOT NULL, `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMARY KEY (`id`), FOREIGN KEY (`subordinate_id`) REFERENCES `user` (`id`), FOREIGN KEY (`leader_id`) REFERENCES `user` (`id`), FOREIGN KEY (`main_leader_id`) REFERENCES `user` (`id`)) ENGINE=InnoDB;
and I found out that the table creation is generated from the model's define because I put other names in the model and the table created was the same as the one I had named the code.
I don't know why the table that is created is in the plural "approvers" and in the model I put the name "approver" and apparently if I try to put another name the plural doesn't happen as well as the word "approver".
the big problem is that I have migrations and when I run them the table "approver" is created in my database, but when I run the command to start the local server, the sequelize creates one more table. So I end up with 2 tables in the database, "approver" of the migration and "approvers" of the model.
I already tried to put the migration and the model with the plural name "approver" but this causes an error when I try to use the model, the sequelize shows a missing field error when I try to create or update data, it says that the value "updatedAt" is missing, and this only happens because the automatically generated table creates this field, but the funniest thing is that the table was not created in my Dbeaver but the sequelize shows the error of being missing a field, even the model containing the plural name and the migration too...
I would like to get the result that the table is not created with the plural.
does anyone know how to solve this bug?
enter image description here
You have two problems here:
An auto-creation of a table according to a model definition
Pluralization of a table name while auto-creating it
Solutions:
Just remove sync call or the whole piece of the following code:
const connect = async () => {
await Approver.sync();
};
connect();
If you use migrations to create the whole structure and to make modifications to it then you don't need to use sync method of a model or a Sequelize instance.
Pluralization of table names can be turned off by indicating 'freezeTableName: true' in the model's options (see Enforcing table name to be equal to a model name in the official documentation).
Related
I am trying to migrate from MySQL to Postgres, I used pgLoader to move my data, reading operations seems to work fine but I am having this issue - When I am trying to create a new record using model.create() I am getting SequelizeDatabaseError: null value in column of relation violates not-null constraint
My sequelize looks like that:
const sequelize = new Sequelize(
process.env.DB_NAME,
process.env.DB_USER,
process.env.DB_PASS,
{
dialect: 'postgres',
host: process.env.DB_HOST,
port: process.env.DB_PORT,
schema: process.env.DB_PORT.DB_SCHEMA,
logging: false,
dialectOptions: {
...(process.env.DB_PORT === "5432" ? {} : addSSL())
}
}
);
const exampleModel = sequelize.define(
"exampleModel",
{
ExampleID: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
Name: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
},
},
);
But when I do:
await model.create({
Name: "FooBaz",
});
I am getting that error.
It was working fine with MySQL but now I am facing this issue.
I am not sure what should I do in this case, because it explicitly say that it's null reseting the counter won't have effect.
Edit:
Running sequelize.sync({alter: true})
prints the following
CREATE TABLE IF NOT EXISTS "schema"."exampleModel" ("ExampleID" SERIAL , "Name" VARCHAR(255) NOT NULL UNIQUE, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL, PRIMARY KEY ("ExampleID"));
Followed by some alter tables lines.
But when I checked ExampleID type it's still integer (as it was on MySQL), the alter doesn't change it.
So do I need to convert it serial manually?
Solved!
The problem is that pgLoader doesn't copy autoincrement correctly, to fix it you need to set it manually on postgres using sequence, check here for instructions.
Changing primary key int type to serial
After fixing it, the problem resolved.
Thank you #a_horse_with_no_name
I have a following table. I don't want user to follow himself so I want to add a CHECK constraint.
For example, if this is inserted, I want database to throw an error.
{
userID: 1,
followingID: 1,
}
I can check with Javascript if userID and followingID are equal but I want database to check it.
My MYSQL version is 8.0.17 so I think it is possible to create this constraint with SQL. How can I add this constraint with Sequelize?
There is two solution
1. Using Model wise validation and adding check constraint in database manually:
Model wise validation:
const FollowingModel = sequelize.define("following", {
userId: {
type: Sequelize.INTEGER,
// .. other configuration like `allowNull`
},
followingId: {
type: Sequelize.INTEGER,
// .. other configuration like `allowNull`
}
}, {
validate: {
userShouldNotFollowSelf : function() {
if(this.userId === this.followingId) {
throw Error("User should not follow self") // Use any custom error class if your application has such class.
}
}
}
}
Beware this will allow you create entry in database which does not maintain this constraint.
It is just ORM's application layer check that, this application won't allow any entry where userId and followingId is not same.
Mysql database layer check constraint.
CREATE TABLE `following`
(
`userId` INT NOT NULL,
`followingId` INT NOT NULL,
CONSTRAINT `no_self_following` CHECK (`userId` <> `followingId`)
-- other properties and foreign key constraints.
);
It will ensure that, no such entry inserted where userId and followingId is same.
2. Declaring constraint in sequelize query interface.
This require to declare your model using query interfaces addConstraint as follows
sequelize.getQueryInterface().addConstraint("following", ['userId'], {
type: 'check',
name: "no_self_following"
where: {
userId: {
[Sequelize.Op.ne]: Sequelize.col("followingId")
}
}
});
Run this while all database model is been synced correctly. It will add database level constraint.
Which one to use ?
Approach #1 is more efficient. It is checking within the application without going into the database call, Makes your database less busy.
im working on a To do list in node using MVC node express pug and sequelize as ORM and the views part i made it with pug, so when i start my app works ok but when i try to create a new proyect and this proyect its gone to insert in the db the error 1364 appears
in principle it is a personal project to add to my portfolio, I saw that there is a possible solution by deactivating the STRICT SQL mode but I would like to know if there is another solution
model code Proyect.js
const Sequelize = require('sequelize');
//conect db
const db = require('../config/db');
const Proyects = db.define('proyects', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false
},
name: Sequelize.STRING,
url: Sequelize.STRING
});
module.exports = Proyects;
I expect with this model create a register in my table but when I try the actual error its the next
Executing (default): CREATE TABLE IF NOT EXISTS `proyects` (`id` INTEGER NOT NULL auto_increment , `name` VARCHAR(255), `url` VARCHAR(255), `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB;
Executing (default): SHOW INDEX FROM `proyects`
conected to db
Executing (default): INSERT INTO `proyects` (`id`,`createdAt`,`updatedAt`) VALUES (DEFAULT,?,?);
{ SequelizeDatabaseError: Field 'id' doesn't have a default value
code: 'ER_NO_DEFAULT_FOR_FIELD',
errno: 1364,
sqlState: 'HY000',
sqlMessage: 'Field \'id\' doesn\'t have a default value',
sql:
'INSERT INTO `proyects` (`id`,`createdAt`,`updatedAt`) VALUES (DEFAULT,?,?);' },
As per my understanding this is a problem with mysql database. The 'id' field in your table is marked as not null, and while inserting values you are not providing any value for the 'id' field.
You can avoid facing this error either allowing null values in the 'id' field or providing a default value (You can use defaultValue flag) while creating the table. Otherwise you already got an alternate solution.
I got this error initially as I had misspelled autoIncrement. To fix this, I used {force:true} as below after applying correct spelling and once the problem was gone, removed it from the sync() method.
I will never use {force:true} in my production deployment as it drops the table (and deletes all your records).
in app.js, call sync method as follows
sequelize.sync({force:true})
.then(result => {
//console.log(result);
app.listen(3000);
})
.catch(err => {
console.log(err);
});
you can install uuid
npm install uuid
then
const uuid = require('uuid')
use it anywhere you want for example
id:uuid.v4()
Please advise on the following issue. I'd like to use Sequelize to work with existing database.
Stack used:
- Node.js v6.10.3
- MySQL 2nd Gen 5.7 running on Google Cloud
- Sequelize 4.7.5
MySQL contains 1 table - 'test_table' with columns 'id', 'content', 'status' and holds some data.
I want to define testTable model which would "explain" my MySQL 'test_table' for sequelize, so I run:
const connection = new Sequelize("dbName", "user", "pass", {
host: xxx.xxx.xxx.xxx,
dialect: mysql
});
const testTable = connection.define('test_table', {
id: {type: Sequelize.INTEGER,
allowNull: false, unique: true,
primaryKey: true, autoIncrement:
true},
content: {type: Sequelize.STRING},
status: {type: Sequelize.STRING},
});
First surprise I get is that from this moment onwards Node completely ignores existence of 'test_table' and creates its 'analogue' (???).
C:\Users\dmitri\Desktop\app>node query.js
Executing (default): CREATE TABLE IF NOT EXISTS `test_tables` (`id` INTEGER NOT NULL auto_increment UNIQUE , `content` VARCHAR(255), `status` INTEGER, `createdAt` DATETIME NOT NULL, `updatedAt` DAT
ETIME NOT NULL, UNIQUE `test_tables_id_unique` (`id`), PRIMARY KEY (`id`)) ENGINE=InnoDB;
Executing (default): SELECT `id`, `content`, `status`, `createdAt`, `updatedAt` FROM `test_tables` AS `test_table`;
Executing (default): SHOW INDEX FROM `test_tables`
Now MySQL contains two tables:
- 'test_table' (singular)
- 'test_tables' (plural) identical to "test_table" but empty.
I am trying to SELECTid,contentFROMtest_table` by executing the following Sequelize code:
testTable
.findAll({attributes: ['id', 'content']})
.then(result=>{
console.log(result)
})
Instead of returning contents of 'test_table', node keeps ignoring it:
C:\Users\dmitri\Desktop\app>node query.js
Executing (default): SELECT id, content FROM test_tables AS test_table;
and returns [].
What may be the reason it voluntarily jumps to query 'test_tables' instead of 'test_table'? Am I completely missing something here?
Many thanks!
You should have specified the table name in the options. Delete this new table, add the table name option and re-lift the app.
connection.define('test_table', {
//.... your fields
}, {
tableName: 'test_table'
});
On a side note, I like to have my models named with camelcase. TestTable. Same goes for connection.define('TestTable'...
EDIT:
As your comments I clarify a couple of things:
You can/have to specify the table name when defining the model. Look at my example. Specifying the tableName property guarantees the pluralization doesnt screw you over.
You shouldnt do sequelize.sync() (unless you know what it does and you want it). Otherwise you might get problems (like sequelize creating another table because it cant find the one it looks for).
Defining the models is something you have to do if you want to use sequelize. Otherwise it doesnt make sense and you should use just mysql2. You have to define the models to match the tables in your database.
How can i rewrite this same schema which is in mongo to mySql
var userSchema = mongoose.Schema({
socketid: String,
username: {
type: String,
unique: true
},
room: String
});
I am not sure whether you are expecting the MySQL create table script for the above schema. If yes, please see below.
users - schema name
You may need to change the schema name accordingly.
Create table users.user_details (
socketid varchar(250),
username varchar(250),
room varchar(1000),
PRIMARY KEY (username)
);
Once the table is created, you can import the JSON data (i.e. MongoDB document JSON) into it. Please refer this link.
You can export the MongoDB collection data using MongoDB export command.