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.
Related
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).
I'm trying to modify a TypeOrm migration script, already running perfectly with MySQL, to work with PostgreSQL.
I got stuck on some table creation with a generated column:
{
name: 'id',
type: 'varchar',
isPrimary: true,
isGenerated: true,
generationStrategy: 'uuid',
}
Not sure why, but I get the following syntax (I left out the working parts):
CREATE TABLE "my_table_name" ("id" NOT NULL DEFAULT uuid_generate_v4(), <some other fields> , CONSTRAINT "<pk>" PRIMARY KEY ("id"))
The migration throws the following error: error: syntax error at or near "NOT", which I narrowed down to the obvious problem of no type declaration between "id" and NOT
If I remove the isGenerated from the config, the type appears and everything works but without the DEAFAULT uuid_generate_v4 part.
I'm not sure what could be the problem, and I'd appreciate your help
Thnx!
Your id type must be 'uuid' to match generation strategy, like this:
{
name: 'id',
type: 'uuid',
isPrimary: true,
isGenerated: true,
generationStrategy: 'uuid',
}
When we use MYSQL we need to know that does not exist NOT NULL, exist IS NOT NULL.
So your code will be
CREATE TABLE "my_table_name" ("id" IS NOT NULL DEFAULT uuid_generate_v4(), <some other fields> , CONSTRAINT "<pk>" PRIMARY KEY ("id")).
https://www.techonthenet.com/mysql/is_not_null.php#:~:text=Example%20%2D%20With%20SELECT%20Statement,not%20contain%20a%20null%20value.
I am currently working with sequelize on RDS Aurora DB and I need to track which records in which tables were deleted - for this, I created a new table dbLog. Now I need to add a trigger to the database which saves the id of the record into dbLog table whenever that record in table t1 gets deleted. Basically, I need to cover two scenarios for already deployed databases and those who dont yet exist.
Database already exists. This is easy since I can create the trigger by raw query like this
CREATE TRIGGER trigger AFTER DELETE ON t1 FOR EACH ROW
INSERT INTO dbLog ( id, tableName, status, updatedAt )
VALUES (OLD.id, 't1', 'D', NOW())`
Database doesn't exist. This is problematic since it gets created by initiation of the model and then sequelize.sync(). So I cant just call a raw query, instead, I need to define this trigger in the model for t1 table. This is how I initiate the table (simplified)
t1.init(
{
id: {
type: new DataTypes.BIGINT,
autoIncrement: true,
primaryKey: true
},
name: {
type: new DataTypes.STRING,
allowNull: false
}
},
{
sequelize,
tableName: 't1',
}
);
The problem is that I dont know how to create that trigger. I tried putting something like this into the attributes section of t1.Init. But there is some problem, when I check the database for triggers, none was created. How can I fix it? And are even triggers created by this way 1:1 equivalent of triggers created by raw query? Thanks a lot.
hooks: {
afterDestroy: function(t1) {
DbLog.create({
id: t1.id,
tableName: 't1',
status: 'D',
updatedAt: '2015-10-02'
})
}
}
You should create triggers in a DB manually by executing a raw SQL query. If you are using migrations then just create a migration with a trigger creation (also a raw SQL query).
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()