Sequelize - Table Pluralization Error, No Instance within Table - mysql

I have run into a weird error where I receive a message for a pluralization version of my database table and it is being grouped into my sequel query. I scanned my models and routes and couldn't find any instance of a pluralization of my table name, and when I check the database tables the structures do not mention any pluralization. When I log the query, it looks like the pluralization error comes in at this section of the query
FROM images AS images LEFT OUTER JOIN descriptions AS description ON
Here is the full error message:
Unhandled rejection SequelizeDatabaseError: ER_NO_SUCH_TABLE: Table 'assistant.descriptions' doesn't exist
Here is my Images model:
module.exports = function(sequelize, DataTypes){
var Images = sequelize.define('images', {
pattern: DataTypes.STRING,
color: DataTypes.STRING,
imageUrl: DataTypes.STRING,
imageSource: DataTypes.STRING,
description_id: DataTypes.INTEGER
}, {
classMethods: {
associate: function(db) {
Images.belongsTo(db.Description, {foreignKey: 'description_id'});
}
}
});
return Images;
}
Here is my Description model:
module.exports = function(sequelize, DataTypes) {
var Description = sequelize.define('description', {
description_id: {
type: DataTypes.INTEGER,
primaryKey: true
},
color: DataTypes.STRING,
body: DataTypes.STRING
});
return Description;
}
Here is how I associate the models in dbIndex:
var Sequelize = require('sequelize');
var sequelize = new Sequelize("assistant", "admin", "pwd", {
host: "host",
port: 3306,
dialect: 'mysql'
});
var db = {};
db.Description = sequelize.import(__dirname + "/descriptionModel");
db.Images = sequelize.import(__dirname + "/imagesModel");
db.Images.associate(db);
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
Here is my query:
router.get('/:pattern/:color/result', function(req, res, image){
console.log(req.params.color);
console.log(req.params.pattern);
db.Images.findAll({
where: {
pattern: req.params.pattern,
color: req.params.color
},
include: [db.Description],
attributes: ['id', 'pattern', 'color', 'imageUrl', 'imageSource', 'description_id']
}).then(function(image){
//console.log(doc.descriptions_id);
res.render('pages/suit-result.hbs', {
pattern : req.params.pattern,
color : req.params.color,
image : image
})
});
});
Here is the query before the error:
Executing (default): SELECT `images`.`id`, `images`.`pattern`, `images`.`color`, `images`.`imageUrl`, `images`.`imageSource`, `images`.`description_id`, `description`.`description_id` AS `description.description_id`, `description`.`color` AS `description.color`, `description`.`body` AS `description.body`, `description`.`createdAt` AS `description.createdAt`, `description`.`updatedAt` AS `description.updatedAt` FROM `images` AS `images` LEFT OUTER JOIN `descriptions` AS `description` ON `images`.`description_id` = `description`.`description_id` WHERE `images`.`pattern` = 'solid' AND `images`.`color` = 'navy-blue';

Seqeulize will pluralize your table names by default. To turn it off, include the option freezeTableName: true to all your model definition options that you don't want pluralized. For example, with the Description model:
var Description = sequelize.define('description', {
description_id: {
type: DataTypes.INTEGER,
primaryKey: true
},
color: DataTypes.STRING,
body: DataTypes.STRING
}, {
freezeTableName: true
});

Related

how to store logs into mysql db using express-winston in Node.js

I am trying to store logs into mysql db(with Sequelize) using express-winston in Node.js.
According to doc(https://www.npmjs.com/package/winston-sql-transport), I should do the following:
const { Logger } = require('winston');
const { SQLTransport } = require('./../lib/winston-sql-transport');
const logger = new Logger({
transports: [
new SQLTransport({
tableName: 'winston_logs',
})]
});
module.exports = logger;
I apply above code in app.js, but not successful.
app.js
const { SQLTransport } = require('./../lib/winston-sql-transport'); // //Error: Cannot find module './../lib/winston-sql-transport'
const mysqlOption = {
tableName: 'winston_logs'
}
app.use(
expressWinston.logger({
transports: [
new SQLTransport(mysqlOption)
],
format: winston.format.combine(
winston.format.timestamp({ format: timezoned }),
winston.format.json(),
),
metaField: null,
expressFormat: true,
statusLevels: false,
level: function (req, res) {
var level = "";
if (res.statusCode < 400) { level = "info"; }
if (res.statusCode >= 400) { level = "warn"; }
if (res.statusCode >= 500) { level = "error"; }
return level;
}
})
)
I tried to change the import to const { SQLTransport } = require('winston-sql-transport');
Resulting error:
Error: You have to define client
at new SQLTransport (/server/node_modules/winston-sql-transport/lib/winston-sql-transport.js:40:13)
I found that people rarely talk about this package.
So I wonder if there is any way to do it?
Update 1:
I updated mysqlOption as suggested by the comment
const { SQLTransport } = require('winston-sql-transport');
const mysqlOption = {
tableName : "winston_logs",
client: 'mysql',
connection: {
host: '127.0.0.1:3306',
user: 'root',
password: '',
database: 'mydb'
}
}
The logs successfully appear in Console, but nothing store in my database.
Update 2:
Since I am using Sequelize, I'm going to provide the schema for the logs table
// See http://docs.sequelizejs.com/en/latest/docs/models-definition/
// for more of what you can do here.
const Sequelize = require('sequelize');
const DataTypes = Sequelize.DataTypes;
module.exports = function (app) {
const sequelizeClient = app.get('sequelizeClient');
const logs = sequelizeClient.define('winston_logs', {
id: {
type: DataTypes.INTEGER(10),
allowNull: false,
autoIncrement: true,
primaryKey: true
},
level: {
type: DataTypes.STRING(45),
allowNull: false
},
message: {
type: DataTypes.TEXT,
allowNull: false
},
meta: {
type: DataTypes.STRING(255),
allowNull: false
},
hostname: {
type: DataTypes.STRING(255),
allowNull: false
},
timestamp: {
type: DataTypes.DATE,
allowNull: false
},
}, {
hooks: {
beforeCount(options) {
options.raw = true;
}
}
});
logs.associate = function (models) {
};
return logs;
};
Finally giving up to store logs in mysql db, since mysql transport package seems a bit outdated.
Instead, I store the logs locally, using winston-daily-rotate-file
It can set the frequency of rotation, Maximum size of the file etc.
link: https://github.com/winstonjs/winston-daily-rotate-file

Association without foreign keys and make join in table

I am working on Node + sequelize + mysql. All the things is working fine in my code. Now i need to add search field in list page. In this search page there is showing user first name, last name, company name and status. I got all data from one table but company comes from "Company" table. In user table there is company_id. I can not make association for company_id. Now i want to search from company_name too. How i add include without association.
const { User, Company } = require("../models");
if(query.trim() != "") {
[err, users] = await to(User.findAll({
where : {[Op.or] : {first_name:{ [Op.like]: '%'+query.trim()+'%' },last_name:{ [Op.like]: '%'+query.trim()+'%' }}},
include : [
{
model:Company,
where : {company_name:{ [Op.like]: '%'+query.trim()+'%' }}
}],
limit: 5,
offset: 0,
order: [[id, ASC]]
}));
console.log('err ----------------',err);
console.log(users);
}
I got below error on from above code :
err ---------------- { filename:
'/var/www/html/fullproject-name/backend/node_modules/sequelize/lib/model.js',
line: 583,
row: 13,
message: 'Company is not associated to User!',
type: 'SequelizeEagerLoadingError',
stack:
'SequelizeEagerLoadingError: Company is not associated to User!\n at Function._getIncludedAssociation..... }
User Model Code :
module.exports = (sequelize, DataTypes) => {
var Model = sequelize.define('User', {
email: {type: DataTypes.STRING, allowNull: true, unique: true, validate: { isEmail: {msg: "Phone number invalid."} }},
company_id: DataTypes.INTEGER,
first_name: DataTypes.STRING,
last_name: DataTypes.STRING,
active:DataTypes.INTEGER,
});
}
Company Model Code :
module.exports = (sequelize, DataTypes) => {
var Model = sequelize.define('Company', {
company_name: DataTypes.STRING,
company_attachment: DataTypes.STRING,
});
}
You need to associate your models with each other in order to be able to query them together with joins. In the below sample, I added some associations for User and Company. The relation I defined (which you can change) is one to many. A user belongs to one company; a company has many users.
This association will put a foreign key of company_id on the User model.
const models = require("./models.js") // Update if necessary
module.exports = (sequelize, DataTypes) => {
var User = sequelize.define("User", { // Changed from Model to User
email: {
type: DataTypes.STRING,
allowNull: true,
unique: true,
validate: { isEmail: { msg: "Phone number invalid." } }
},
company_id: DataTypes.INTEGER,
first_name: DataTypes.STRING,
last_name: DataTypes.STRING,
active: DataTypes.INTEGER
});
User.belongsTo(models.Company); // User to Company association
};
const models = require("./models.js") // Update if necessary
module.exports = (sequelize, DataTypes) => {
var Company = sequelize.define("Company", { // Changed from Model to Company
company_name: DataTypes.STRING,
company_attachment: DataTypes.STRING
});
Company.hasMany(models.User); // Company to User association
};

assotiating two tables in sequelize

Im having problems associating 2 models. I will try to describe the problem as detailed as possible and hope you can help me.
I have 2 Models: Zone and PLZ (both are also tables in database-mysql).
There can be One Zone having many PLZs and one PLZ can belong to One zone.
On saving a zone with its PLZs I have a table called "zone_plz" with only two columns: zone_id and plz_id. Both have foreign keys to Zone.id and PLZ.id
Zone Model:
const Sequelize = require('sequelize');
const sequelize = require('../util/database');
const PLZ = require('../models/PLZ');
const zone_plz = require('../models/relations/zone_plzs');
const Zone = sequelize.define('zone', {
name: {
type: Sequelize.STRING,
allowNull: false
},
color: {
type: Sequelize.STRING,
allowNull: false
}
}, {
timestamps: true
});
module.exports = Zone;
PLZ model:
const Sequelize = require('sequelize');
const sequelize = require('../util/database');
const Zone = require('../models/Zone');
const zone_plz = require('../models/relations/zone_plzs');
const PLZ = sequelize.define('plz', {
plz: {
type: Sequelize.INTEGER,
allowNull: false
},
city: {
type: Sequelize.STRING,
allowNull: false
},
district: {
type: Sequelize.STRING
}
});
module.exports = PLZ;
and this is the zone_plz model:
const Sequelize = require('sequelize');
const sequelize = require('../../util/database');
const PLZ = require('../../models/PLZ');
const Zone = require('../../models/Zone');
const zone_plz = sequelize.define('zone_plz', {
zone_id: {
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: Zone,
key: 'id',
}
},
plz_id: {
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: PLZ,
key: 'id',
}
}
}, {
timestamps: true
});
module.exports = zone_plz;
and this is how I query it:
router.get('/', function (req, res, next) {
zone_plz.findAll({
include: [{
model: PLZ,
as: 'plz'
},
{
model: Zone,
as: 'zone'
}]
}).then((result) => {
res.send({status: true, data: result})
}).catch(function (err) {
next(err)
})
});
As you can see i want to return a zone with all the belonging plzs to the user.
Im new to sequelize and Im also not sure if this is the right approach. I get the error: plz is not associated to zone_plz!
Can anyone help me?
You created references, not associations. Please, first of all, read the differences: Sequelize model references vs associations
then create associations between plz & zone like:
plz.belongsToMany(zone, {through: 'zone_plz'});
zone.belongsToMany(plz, {through: 'zone_plz'});

How to query many-to-many relationship data in Sequelize

I have got a many-to-many relationship between two models, users and groups.
I have two models which are specifying the belongsToMany with a foreignKey and through attribute.
Users model
'use strict';
module.exports = function(sequelize, DataTypes) {
var User = sequelize.define('User', {
firstName: DataTypes.STRING,
lastName: DataTypes.STRING,
email: DataTypes.STRING,
username: DataTypes.STRING,
facebookId: DataTypes.STRING,
password: DataTypes.STRING,
}, {
classMethods: {
associate: function(models) {
User.hasMany(models.Payment);
User.hasMany(models.Friend, {foreignKey: 'userIdLink1'});
User.belongsToMany(models.Group, { through: 'UsersGroups', foreignKey: 'facebookId' });
}
},
instanceMethods: {
toJSON: function () {
var values = Object.assign({}, this.get());
delete values.password;
return values;
}
}
});
return User;
};
groups model
'use strict';
module.exports = function(sequelize, DataTypes) {
var Group = sequelize.define('Group', {
name: DataTypes.STRING
}, {
classMethods: {
associate: function(models) {
// associations can be defined here
Group.belongsToMany(models.User, {through: 'UsersGroups', foreignKey: 'groupId'});
Group.hasMany(models.Payment)
}
},
instanceMethods: {
toJSON: function () {
var values = Object.assign({}, this.get());
delete values.password;
return values;
}
}
});
return Group;
};
which are being joined via a junction table UsersGroups
This works fine and I can create a new group and it links the user with it successfully but when I try fetch the data the SQL query is trying to find Groups based on User.id as opposed to User.facebookId like I specified in my model User.belongsToMany(models.Group, { through: 'UsersGroups', foreignKey: 'facebookId' });
I call the following code to fetch the data:
const options = {
where: {
facebookId: facebookId,
},
defaults: {
firstName: data.firstName,
lastName: data.lastName,
email: data.email,
facebookId: facebookId
},
include: [
{ model: db.Group }
]
}
db.User.findOrCreate(options)
.then((user) => {
res.send(user)
}, (err) => {
res.status(500).send(err)
})
and it returns a user but with an empty Groups array which is incorrect as there is definitely data there as I can create it fine and see it in the DB.
You can see the SQL query that is generated by Sequelize here:
SELECT `User`.*, `Groups`.`id` AS `Groups.id`, `Groups`.`name` AS `Groups.name`, `Groups`.`createdAt` AS `Groups.createdAt`, `Groups`.`updatedAt` AS `Groups.updatedAt`, `Groups.UsersGroups`.`createdAt` AS `Groups.UsersGroups.createdAt`, `Groups.UsersGroups`.`updatedAt` AS `Groups.UsersGroups.updatedAt`, `Groups.UsersGroups`.`facebookId` AS `Groups.UsersGroups.facebookId`, `Groups.UsersGroups`.`groupId` AS `Groups.UsersGroups.groupId`
FROM (
SELECT `User`.`id`, `User`.`firstName`, `User`.`lastName`, `User`.`email`, `User`.`username`, `User`.`facebookId`, `User`.`password`, `User`.`createdAt`, `User`.`updatedAt` FROM `Users` AS `User` WHERE `User`.`facebookId` = '1341052992643877' LIMIT 1) AS `User`
LEFT OUTER JOIN (`UsersGroups` AS `Groups.UsersGroups`
INNER JOIN `Groups` AS `Groups` ON `Groups`.`id` = `Groups.UsersGroups`.`groupId`
)
ON `User`.`id` = `Groups.UsersGroups`.`facebookId`;
Note the last line
ON `User`.`id` = `Groups.UsersGroups`.`facebookId`
needs to be
ON `User`.`facebookId` = `Groups.UsersGroups`.`facebookId`
Turns out I had to specify facebookId as a primary key in my user model
facebookId: {
type: DataTypes.STRING,
primaryKey: true,
},

Sequelize Many To Many Relationship : Cannot read property 'split' of undefined

I'm trying to create many to many relationship using Sequelize + nodeJs using existing MySQL Database :
Below is my tables :
- "usr" Table : usr_id (PK)
- Intermediate "usr_role" : usr_id, role_id
- "role" table : role_id
This is my models
"User" Models:
"use strict";
var bcrypt = require('bcryptjs');
module.exports = function(sequelize, DataTypes) {
var User = sequelize.define('User', {
usrid : {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false,
field:'usr_id'
},
name :{
type: DataTypes.STRING,
allowNull: false,
field:'usr_name'
},
}, {
timestamps: false,
freezeTableName: true,
tableName: 'usr',
name:'User',
underscored:'true',
classMethods: {
associate:function(models){
User.belongsToMany(models.Role, { through: 'UserRole', foreignKey:'usr_id', as:'UserRoles'});
}
}
}
);
return User;
};
"Role" models
module.exports = function(sequelize, DataTypes) {
var Role = sequelize.define('Role', {
id : {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false,
field:'role_id'
},
name :{
type: DataTypes.STRING,
allowNull: false,
field:'role_name'
},
},{
timestamps: false,
freezeTableName: true,
tableName: 'role_ref',
underscored:'true',
classMethods: {
associate:function(models){
Role.belongsToMany(models.User, {
through: 'UserRole',
foreignKey:'role_id'});
}
}
}
)
return Role;
};
E:\nodejsWS\learn\node_modules\inflection\lib\inflection.js:795
var str_path = str.split( '::' );
^
TypeError: Cannot read property 'split' of undefined
at Object.inflector.underscore
(E:\nodejsWS\learn\node_modules\inflection\lib\inflection.js:795:25)
at Object.module.exports.underscoredIf
(E:\nodejsWS\learn\node_modules\sequelize\lib\utils.js:28:27)
at new BelongsToMany (E:\nodejsWS\learn\node_modules\sequelize
\lib\associations\belongs-to-many.js:134:15)
at Mixin.belongsToMany
(E:\nodejsWS\learn\node_modules\sequelize\lib\associations
\mixin.js:264:21)
at sequelize.define.classMethods.associate
(E:\nodejsWS\learn\models\Role.js:29:12)
at E:\nodejsWS\learn\models\index.js:50:21
this is my index.js
// Import models
fs
.readdirSync(__dirname)
.filter(function(file) {
return (file.indexOf(".") !== 0) && (file !== "index.js");
})
.forEach(function(file) {
var model = sequelize.import(path.join(__dirname, file));
db[model.name] = model;
});
//associate models
Object.keys(db).forEach(function(modelName) {
if ("associate" in db[modelName]) {
console.log(db);
db[modelName].associate(db);
}
});
Line 50 refer to db[modelName].associate(db), that cause the error.
Can somebody please guide me what's i'm doing wrong. Do i need to manually create intermediate Models 'UserRole'. Your help is very much appreciated. Thanks.
You need to specify the actual intermediate table's name in the belongsToMany config, or define the model UserRole. Also, unless your intermediate table has the fields, you'll probably also want to specify timestamps: false as well. So, for example:
Role.belongsToMany(models.User, {
through: 'usr_role',
foreignKey:'role_id',
timestamps: false
});
This will cause sequelize to use that table in the queries it builds without needing a model defined, and will prevent it from requesting the timestamp fields from either the User table or the intermediate.