How to define an index, within a Sequelize model? - mysql

I'm trying to create a simple non-unique index for one of my SQL columns, inside a Sequelize model. I tried to follow this post :How to define unique index on multiple columns in sequelize .
This is my code:
module.exports = (sequelize, DataTypes) => {
const Item = sequelize.define('Item', {
itemId: DataTypes.STRING,
ownerId: DataTypes.INTEGER,
status: DataTypes.STRING,
type: DataTypes.STRING,
nature: DataTypes.STRING,
content: DataTypes.STRING,
moment: DataTypes.BIGINT,
indexes:[
{
unique: 'false',
fields:['ownerId']
}
]
});
return Item;
};
I get this error:
Unhandled rejection SequelizeDatabaseError: You have an error in your
SQL syntax; check the manual that corresponds to your MariaDB server
version for the right syntax to use near '[object Object], createdAt
DATETIME NOT NULL, updatedAt DATETIME NOT NULL, P' at line 1
The code that i have in my server.js file is this:
models.sequelize.sync().then(function () {
server.listen(port, () => {
console.log('server ready')
})
});
What is wrong with my setup? Is there any other way this can be done with Sequelize?

Almost there. You should add indexes in a new object like this:
module.exports = (sequelize, DataTypes) => {
const Item = sequelize.define('Item', {
itemId: DataTypes.STRING,
ownerId: DataTypes.INTEGER,
status: DataTypes.STRING,
type: DataTypes.STRING,
nature: DataTypes.STRING,
content: DataTypes.STRING,
moment: DataTypes.BIGINT
},
{
indexes:[
{
unique: false,
fields:['ownerId']
}
]
});
return Item;
};

It can work in single migration also.
In my case, just perform the addIndex after createTable method in the migration file
Migration:
return queryInterface.createTable('Item', {
// columns...
}).then(() => queryInterface.addIndex('Item', ['OwnerId']))
.then(() => {
// perform further operations if needed
});
it's work for me in the migration file.

Related

Sequelize error "Unknown column in 'field list'" during CREATE for One-to-Many Association

I have been using the following tutorial to learn how to implement one-to-many relationship in Sequelize where a Tutorial has many Comment and Comment belongs to a Tutorial: https://www.bezkoder.com/sequelize-associate-one-to-many/
While I have the code modeling what is documented for setting up the relationship between the two models, I receive the following error during creating the Comment model:
Unknown column 'tutorialId' in 'field list'
Additionally, I receive the following SQL output:
Executing (default): INSERT INTO `comments` (`id`,`name`,`text`,`createdAt`,`updatedAt`,`tutorialId`) VALUES (DEFAULT,?,?,?,?,?);
app.js
const tutorialsRouter = require('./routes/api/tutorials');
const commentsRouter = require('./routes/api/comments');
app.use('/api/tutorials', tutorialsRouter);
tutorialsRouter.use('/:tutorialId/comments', commentsRouter);
/models/index.js
db.tutorials = require("./tutorial.model")(sequelize, Sequelize);
db.comments = require("./comment.model")(sequelize, Sequelize);
db.tutorials.hasMany(db.comments, { as: "comments" });
db.comments.belongsTo(db.tutorials, {
foreignKey: "tutorialId",
as: "tutorial",
});
/models/comment.model.js
module.exports = (sequelize, DataTypes) => {
const Comment = sequelize.define('comment', {
name: {
type: DataTypes.STRING,
},
text: {
type: DataTypes.STRING,
},
});
return Comment;
}
/routes/comments.js
const comments = require('../../controllers/comments.controller');
const router = require('express').Router({ mergeParams: true });
router.post('/', comments.create);
module.exports = router;
/controllers/comments.controller.js
const db = require('../models');
const Comment = db.comments;
exports.create = (req, res) => {
...
Comment.create({
name: req.body.name,
text: req.body.text,
tutorialId: req.params.tutorialId,
})
.then( ... )
.catch( ... );
}
Then in Postman I receive a 500 (of the error message above) when issuing the request:
POST localhost:3000/api/tutorials/1/comments
{
"name": "John Doe",
"text": "Lorem ipsum..."
}
I don't think I should have to define a tutorialId field on the Comment model. Grr...
This may be very obvious to some of you, but it's tripping me up trying to learn. Any help is very much appreciated. :)
The issue that you're having is a result of using aliases via the as property. See the docs for belongsTo and hasMany. Here's a code sample that performs the inserts without the error.
let {
Sequelize,
DataTypes,
} = require('sequelize')
async function run () {
let sequelize = new Sequelize('dbname', 'username', 'password', {
host: 'localhost',
port: 5555,
dialect: 'postgres',
logging: console.log
})
let Comment = sequelize.define('comment', {
name: {
type: DataTypes.STRING,
},
text: {
type: DataTypes.STRING,
},
})
let Tutorial = sequelize.define('tutorial', {
title: {
type: DataTypes.STRING,
},
content: {
type: DataTypes.STRING,
}
})
Tutorial.hasMany(Comment)
Comment.belongsTo(Tutorial)
// This just recreates the tables in the database.
// You would really only want to use a force sync
// in a development environment, since it will destroy
// all of the data....
await sequelize.sync({ force: true })
let tutorial = await Tutorial.create({
title: 'Tutorial',
content: 'Hmm....'
})
let comment = await Comment.create({
name: 'Comment',
text: 'Something, something....',
tutorialId: tutorial.id,
})
await sequelize.close()
}
run()
Edit
This is just an edit to my original answer above. The OP Tom Doe discovered that the issue was being caused by a mismatch between the definitions of the tables in the database and the models defined via sequelize (see comments below). As we discovered, one way to troubleshoot the mismatch is to force sync a new version of the database, and then compare the new version of the database with the original version. There may be differences in the definitions of the columns or the contraints. Force syncing the database can be done via the command
await sequelize.sync({ force: true})
Important Note: The above statement will overwrite the existing database and all of its data. See the docs for more information.

Sequelize in Nodejs creating duplicate tables upon app start

Ok. Landscape: Node, MySql, Sequelize
Issue: After creating a new data model & migration (node migrate.js which creates just fine), upon app start Sequelize creates a duplicate Table (and also forwards form data to the new table).
Ex: db.virtual_class is the main table, and upon start, db.virtual_classes is also created.
My model:
const Sequelize = require('sequelize');
const sequelize = require('../sequelize');
const model = sequelize.define('virtual_class', {
id: { type: Sequelize.INTEGER, autoIncrement: true, primaryKey: true },
style: Sequelize.STRING, // e.g. Style of class
description: Sequelize.STRING(1024), // e.g. class Details
jwt_secret: Sequelize.STRING, // e.g. rando string to be used to gen unique keys for every room
});
module.exports = model;
I've isolated what I think is the issue - I'm including the model in a variable on my index controller for my functions.
const Virtual_class = require('./model');
const classQuery = require('./classQuery');
async function addClass({ style, description, secret }) {
const vClass = await Virtual_class.create({
style,
description,
jwt_secret: secret,
}, { raw: true });
return classQuery(vClass);
}
module.exports = {
addClass,
};
Class Query function to return the data in a usable object:
function classQuery(queryResult) {
if (!queryResult) {
return null;
}
return {
id: queryResult.id,
style: queryResult.style,
description: queryResult.description,
secret: queryResult.jwt_secret,
};
}
module.exports = classQuery;
and the migration:
module.exports = {
up: (sequelize, Sequelize) => sequelize.getQueryInterface().createTable('virtual_class', {
id: {
type: Sequelize.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true,
},
style: {
type: Sequelize.STRING,
},
description: {
type: Sequelize.STRING,
},
jwt_secret: {
type: Sequelize.STRING,
},
createdAt: {
type: Sequelize.DATE,
allowNull: false,
defaultValue: Sequelize.fn('now'),
},
updatedAt: {
type: Sequelize.DATE,
allowNull: false,
defaultValue: Sequelize.fn('now'),
},
}),
down: sequelize => sequelize.getQueryInterface().dropTable('virtual_class'),
};
Net result is fine before I run app - DB shows new table, After running app - DB shows dup table.
I'm a relative noob, and been wracking my brain (and trying to find solutions here) to the problem. I've done this before with other migrations with no issue.
Any advice is appreciated! Thanks!
DOH! For those who are new like me - Sequelize automatically creates plural tables by default, You can force the override tp singular table names.

'Table not found' error when inserting row. Sequelize and nodejs

When I'm trying to import user into database with User.create(), sequelize trows me error that says that table doesn't exist. Even tho I created a table line above the create function. My goal is to add user without using .then() function on .sync function.
I've tried to put sync function in await as I imagined that the sync function takes longer to finish.
// imports ...
// Connecting to database
// Creating ORM object
const db = new sequelize(format("%s://%s:%s#%s:%s/%s", gvars.db_soft, gvars.db_user, gvars.db_pass, gvars.db_host, gvars.db_port, gvars.db_daba));
db.authenticate().then(() => {
console.log("Connection established.");
}).catch(err => {
console.error(err);
});
// Define users table
const User = db.define("users", {
firstName: {
type: sequelize.STRING,
allowNull: false
},
lastName: {
type: sequelize.STRING,
allowNull: false
}}, { freezeTableName: true,
});
db.sync({ force: true }).then(() => { console.log("Table created."); });
User.create({
firstName: "Milan",
lastName: "Vjestica"
});
//...starting app
I expect for user to be added in table.
You have to use promise in sequelize as it is a promised based ORM,try following changes:
User.create({ firstName: "Milan",lastName: "Vjestica"}).then(function(user)
{
console.log(user.get('firstName'));
console.log(user.get('lastName'));
});

Sequelize associations not being created in MySQL, PostgreSQL and SQLite

I am defining associations in models using sequalize with MYSQL. But after migration, the foreign key is not being added to the target model as explained in sequelize docs.
I have also tried to manually define foreign keys in models and migration files but still no association is being created between tables. When I view the tables in relation view in PhpMyAdmin, not foreign key constraints or relationship is being created.
I have tried this with SQLite, and PostgreSQL with the same results. I don't know what I am doing wrong. Here are models.
AURHOR MODEL
//One author hasMany books
'use strict';
module.exports = (sequelize, DataTypes) => {
const Author = sequelize.define('Author', {
Name: DataTypes.STRING
}, {});
Author.associate = function(models) {
// associations can be defined here
Author.hasMany(models.Book)
};
return Author;
};
I expect sequelize to add authorId on books table as specified in the docs, but this not happening
BOOK MODEL
//Book belongs to Author
'use strict';
module.exports = (sequelize, DataTypes) => {
const Book = sequelize.define('Book', {
Title: DataTypes.STRING
}, {});
Book.associate = function(models) {
// associations can be defined here
Book.belongsTo(models.Author)
};
return Book;
};
No associations is being created between these two tables after migration.
I have as well tried to define custom foreign keys in model associations like this:
//Author model
Author.hasMany(models.Book,{foreignKey:'AuthorId'})
//Book model
Book.belongsTo(models.Author,{foreignKey:'AuthorId'})
still this not solving the problem
I have gone ahead to define foreign keys in models then referencing them in the association like this:
'use strict';
module.exports = (sequelize, DataTypes) => {
const Book = sequelize.define('Book', {
Title: DataTypes.STRING,
AuthorId:DataTypes.INTEGER
}, {});
Book.associate = function(models) {
// associations can be defined here
Book.belongsTo(models.Author,{foreignKey:'AuthorId'})
};
return Book;
};
But still no associations is being created
I finally decided to add references in migration files like so:
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Books', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
Title: {
type: Sequelize.STRING
},
AuthorId:{
type: Sequelize.INTEGER,
references:{
model:'Author',
key:'id'
}
}
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Books');
}
};
But when I run this kind of migration setup, I get this error: ERROR: Can't create table dbname.books (errno: 150 "Foreign key constraint is i
ncorrectly formed")
I get similar error when I switch to PostgreSQL.
I have been held back by this issue for quite long. What may I doing wrong. I am using sequelize version 4.31.2 with sequelize CLI.
I was referencing to models wrongly in migrations.
Wrong way
AuthorId:{
type: Sequelize.INTEGER,
references:{
model:'Author',
key:'id'
}
}
Correct Way
// Notes the model value is in lower case and plural just like the table name in the database
AuthorId:{
type: Sequelize.INTEGER,
references:{
**model:'authors',**
key:'id'
}
}
This solved my problem. The associations is now getting defined.

Async await in mysql seeding does not run

I am trying to seed my MySQL database. I am using the Sequelize ORM. In my index.js file which is in the models folder, I have the code to run the realSync() function for every model as such :
const syncDB = async () => {
await db['Meal'].realSync();
await db['User'].realSync();
}
syncDB();
And in my 'Meal' file, I have the following:
const mealSeeds = require("../scripts/mealSeeds");
module.exports = (sequelize, DataTypes) => {
let Meal = sequelize.define("Meal", {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
name: DataTypes.STRING,
type: DataTypes.STRING,
description: DataTypes.STRING,
photo_URL: DataTypes.STRING,
allergen_dairy: DataTypes.BOOLEAN,
allergen_treenuts: DataTypes.BOOLEAN,
allergen_peanuts: DataTypes.BOOLEAN,
allergen_wheat: DataTypes.BOOLEAN,
allergen_fish: DataTypes.BOOLEAN,
allergen_crustaceanshellfish: DataTypes.BOOLEAN,
allergen_eggs: DataTypes.BOOLEAN,
allergen_soya: DataTypes.BOOLEAN,
date_available: DataTypes.DATE,
time_available: DataTypes.TIME,
quantity: DataTypes.INTEGER,
zipcodes: DataTypes.JSON,
catererId: {
field: "CatererId",
type: DataTypes.INTEGER,
allowNull: true,
defaultValue: 0
}
})
Meal.associate = function (models) {
Meal.belongsTo(models.User, {
foreignKey: "catererId",
targetKey: "id"
})
}
// // Insert the meal seed data
Meal.realSync = async () => {
await Meal.sync()
return await Meal.bulkCreate(mealSeeds,
{ignoreDuplicates: true}
);
};
return Meal;
}
Where the Meal.realSync is supposed to seed the Meals table with data from the mealSeeds.js file in the scripts directory. (And I have a User.js file with the user table fields and a similar .realSync() function for the User table. And this function is working just fine, and users are being seeded into the db).
This function was working fine for weeks, as I was building the project, and recently after changing some of the fields in the 'Meal' table, it no longer works. My previous research shows that by calling the realSync() function asynchronously in the index.js file, it will run and wait for the Meal realSync() function to complete before running the User realSync() function. I am not sure why it no longer runs the first function at all. Any help would be greatly appreciated.
Solved-I figured out that my seed data did not contain a foreign key reference.