How to define an array in my models using mysql sequelize | node.js - mysql

This is the result what I need to store in DB :
sellers : [{'test1'},{'test2'},{'test3'}]
And this is my model:
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define(
"User",
{
id: {
allowNull: false,
primaryKey: true,
autoIncrement: true,
type: DataTypes.INTEGER,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
},
password: {
type: DataTypes.STRING,
allowNull: false,
},
sellers: [
{
type: DataTypes.STRING,
allowNull: true,
},
],
},
{
timestamps: true,
defaultScope: {
attributes: {
exclude: ["password"],
},
},
scopes: {
withPassword: {
attributes: {},
},
},
indexes: [
{
unique: true,
fields: ["email"],
},
],
}
);
return User;
};
And the error is :
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near

sellers: [
{
type: DataTypes.ARRAY(DataTypes.STRING),
allowNull: true,
}

You need to slightly change your schema definition as,
sellers: {
type: DataTypes.ARRAY(DataTypes.JSON),
allowNull: true,
defaultValue: [{}],
get() {
const data = this.getDataValue('sellers');
const queryResponse = [];
data.forEach(seller => {
queryResponse.push(JSON.parse(seller));
});
return queryResponse;
},
set(seller) {
return this.setDataValue('sellers', JSON.stringify(seller));
}
},

Related

Sequelize belongsTo query results in belongsTo called with something that's not a subclass of Sequelize.Model error

I am trying to write a join query using belongsTo but getting error:
Error: LearningCertificateEvent.belongsTo called with something that's
not a subclass of Sequelize.Model
at Function. (/Users/msmexmac/node/msmex-backend/msmex-api/node_modules/sequelize/lib/associations/mixin.js:93:13)
I am trying to fetch events related to learning cerfificate events. I tried every thing but it does not work somehow.
My models are as follows:
LearningCertificate Model
"use strict";
const Sequelize = require("sequelize");
const sequelize = require("../helpers/db");
const LearningCertificateEvent = require("./LearningCertificateEvent");
const LearningCertificate = sequelize.define(
"LearningCertificate",
{
id: {
autoIncrement: true,
type: Sequelize.BIGINT,
primaryKey: true,
},
userId: {
type: Sequelize.INTEGER,
field: "user_id",
},
certificateURL: {
type: Sequelize.STRING,
field: "certificate_url",
},
certificatePNGURL: {
type: Sequelize.STRING,
field: "certificate_png_url",
},
certificateType: {
type: Sequelize.STRING,
field: "certificate_type",
},
createdAt: {
type: Sequelize.BIGINT,
field: "created_at",
},
updatedAt: {
type: Sequelize.BIGINT,
field: "updated_at",
},
},
{
timestamps: false,
tableName: "learning_certificate",
}
);
LearningCertificate.hasMany(LearningCertificateEvent, {
foreignKey: "certificateId",
});
module.exports = LearningCertificate;
The second model is : LearningCertificateEvent Model
"use strict";
const Sequelize = require("sequelize");
const sequelize = require("../helpers/db");
const MsmexEvent = require("./MsmexEvent");
const LearningCertificateEvent = sequelize.define(
"LearningCertificateEvent",
{
id: {
autoIncrement: true,
type: Sequelize.BIGINT,
primaryKey: true,
},
userId: {
type: Sequelize.INTEGER,
field: "user_id",
},
certificateId: {
type: Sequelize.INTEGER,
field: "certificate_id",
},
eventId: {
type: Sequelize.INTEGER,
field: "event_id",
},
createdAt: {
type: Sequelize.BIGINT,
field: "created_at",
},
updatedAt: {
type: Sequelize.BIGINT,
field: "updated_at",
},
},
{
timestamps: false,
tableName: "learning_certificate_event",
}
);
LearningCertificateEvent.belongsTo(MsmexEvent, {
foreignKey: "eventId",
});
// MsmexEvent.hasMany(LearningCertificateEvent, {
// foreignKey: "eventId",
// });
module.exports = LearningCertificateEvent;
And last model is: MsmexEvent Model
"use strict";
const Sequelize = require("sequelize");
const sequelize = require("../helpers/db");
const LearningCertificateEvent = require("./LearningCertificateEvent");
const Event = sequelize.define(
"Event",
{
id: {
autoIncrement: true,
type: Sequelize.BIGINT,
primaryKey: true,
},
identifier: {
type: Sequelize.STRING,
field: "identifier",
},
expertId: {
type: Sequelize.INTEGER,
field: "expert_id",
},
waitList: {
type: Sequelize.BOOLEAN,
field: "waitList",
},
},
{
timestamps: false,
tableName: "msmex_event",
}
);
module.exports = Event;
The query which I have written is as follows:
return LearningCertificate.findAll({
where: {
userId: userId,
},
include: [
{
model: LearningCertificateEvent,
required: true,
include: [
{
model: MsmexEvent,
required: true,
},
],
},
],
order: [["id", "DESC"]],
});
In query however if I replace MsmexEvent with some other table for example User it works fine.
Can some one please help ?

Sequelize returning one result when counting AVG in Eager Loading

I have been trying to fix this problem for a day now but no luck. I am using Sequelize With Nodejs and MySQL dialect.
I am querying for Influencers whilst also calculating their average ratings from a InfluencerRating record. They are associated through a oneToMany relation.
Here is my Influencer modal:
const Sequelize = require('sequelize');
module.exports = function(sequelize, DataTypes) {
return sequelize.define('influencer', {
id: {
autoIncrement: true,
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true
},
display_name: {
type: DataTypes.STRING(255),
allowNull: false
},
link_facebook: {
type: DataTypes.STRING(255),
allowNull: true
},
link_soundcloud: {
type: DataTypes.STRING(255),
allowNull: true
},
link_twitter: {
type: DataTypes.STRING(255),
allowNull: true
},
link_bandcamp: {
type: DataTypes.STRING(255),
allowNull: true
},
link_spotify: {
type: DataTypes.STRING(255),
allowNull: true
},
link_instagram: {
type: DataTypes.STRING(255),
allowNull: true
},
link_deezer: {
type: DataTypes.STRING(255),
allowNull: true
},
link_youtube: {
type: DataTypes.STRING(255),
allowNull: true
},
link_website: {
type: DataTypes.STRING(255),
allowNull: true
},
description_english: {
type: DataTypes.STRING(255),
allowNull: true
},
description_french: {
type: DataTypes.STRING(255),
allowNull: true
},
information_english: {
type: DataTypes.STRING(255),
allowNull: true
},
information_french: {
type: DataTypes.STRING(255),
allowNull: true
},
enabled: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: 0
},
profile_image: {
type: DataTypes.STRING(255),
allowNull: true
},
banner_image: {
type: DataTypes.STRING(255),
allowNull: true
},
admin_public_status: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: 1
}
}, {
sequelize,
tableName: 'influencer',
timestamps: false,
underscored: true,
indexes: [
{
name: "PRIMARY",
unique: true,
using: "BTREE",
fields: [
{ name: "id" },
]
},
]
});
};
Here is my InfluencerRating modal:
module.exports = function(sequelize, DataTypes) {
return sequelize.define('influencer_rating', {
id: {
autoIncrement: true,
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true
},
description: {
type: DataTypes.STRING(255),
allowNull: false
},
influencer_id: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: 'influencer',
key: 'id'
}
},
rating: {
type: DataTypes.INTEGER,
allowNull: false
}
}, {
sequelize,
tableName: 'influencer_rating',
timestamps: false,
underscored: true,
indexes: [
{
name: "PRIMARY",
unique: true,
using: "BTREE",
fields: [
{ name: "id" },
]
},
{
name: "type_id",
using: "BTREE",
fields: [
{ name: "influencer_id" },
]
},
]
});
};
And here is my associations between them both:
influencer_rating.belongsTo(influencer, { as: "influencer", foreignKey: "influencer_id"});
influencer.hasMany(influencer_rating, { as: "influencer_ratings", foreignKey: "influencer_id"});
Here is my query to find influencers and calculate their average ratings:
var influencers = await Influencer.findAll(
{
where: {
[db.Op.and]: [
{
enabled: true
},
{
display_name: {
[db.Op.like]: '%' + filter + '%'
}
},
{
admin_public_status: true
}
],
},
include: [
[
{
model: InfluencerRating,
as: "influencer_ratings",
required: false,
attributes: [[Sequelize.fn('AVG', Sequelize.col('rating')), 'rating']]
}
],
limit: 10,
offset: 0,
group: ['id']
}
);
The query should be returning 2 influencer Objects, but I am only getting one.
I get the wanted behaviour if I delete my :
attributes: [[Sequelize.fn('AVG', Sequelize.col('rating')), 'rating']]
I have tried calculating my average outside of my InfluencerRating include but not luck.
Made some changes to findAll. Can give it a try:
var influencers = await Influencer.findAll({
// whenever hasMany used in include, the main query gets converted to subquery
// if limit + offset is applied
subQuery: false, // <----- instructs not to make a sub query
attributes: {
include: [
[Sequelize.fn('AVG', Sequelize.col('influencer_ratings.rating')), 'total_rating']
],
},
where: {
[db.Op.and]: [
{ enabled: true },
{ display_name: { [db.Op.like]: '%' + filter + '%' } },
{ admin_public_status: true }
],
},
include: [ // removed extra nesting of array
{
model: InfluencerRating,
as: "influencer_ratings",
required: false,
attributes: [],
}
],
limit: 10,
offset: 0,
group: [
'id',
// 'influencer_ratings.influencer_id', // add if sql error occurs
],
order: [ // if needed
[Sequelize.literal('total_rating'), 'DESC'],
]
});
Few reference links:
Disable sub query generation(done by sequelize) when hasMany/belongsToMany relation included - https://github.com/sequelize/sequelize/issues/1756#issuecomment-54748245
Using SQL sub queries with ordering: https://sequelize.org/master/manual/sub-queries.html
Alternate approach:
var influencers = await Influencer.findAll({
attributes: {
include: [
[Sequelize.literal(`(
SELECT
AVG("influencer_ratings"."rating") AS "avg_rating"
FROM
"influencer" AS "influencer1"
LEFT OUTER JOIN (
"influencer_ratings" AS "influencer_ratings"
) ON "influencer1"."id" = "influencer_ratings"."influencer_id"
WHERE
"influencer1"."id" = "influencer"."id"
GROUP BY
"influencer1"."id"
)`), 'avg_rating'], // now this is just a subquery and will not interfere with other includes
],
},
where: {
[db.Op.and]: [
{ enabled: true },
{ display_name: { [db.Op.like]: '%' + filter + '%' } },
{ admin_public_status: true }
],
},
include: [ // removed extra nesting of array
// influencer_ratings include not needed now
// add other includes as needed
],
limit: 10,
offset: 0,
order: [ // if needed
[Sequelize.literal('avg_rating'), 'DESC'],
]
});

Could not find migration method: up

I am unable to migrate my models to MySQL db. It's throwing me the below error:
Loaded configuration file "config\config.json".
Using environment "development".
(node:5828) [SEQUELIZE0004] DeprecationWarning: A boolean value was passed to options.operatorsAliases. This is a no-op with v5 and should be removed.
== 20191218125700-mig_admin_roles: migrating =======
ERROR: Could not find migration method: up
models- admin_user.js
module.exports = (sequelize, DataTypes) => {
{
var admin_users = sequelize.define("adminUser", {
id: {
type: DataTypes.INTEGER(22),
allowNull: false,
primaryKey: true,
autoIncrement: true,
field: "id"
},
fname: {
type: DataTypes.STRING(20),
allowNull: false,
field: "fname"
},
lname: {
type: DataTypes.STRING(20),
allowNull: true,
field: "lname"
},
phoneNo: {
type: DataTypes.STRING(20),
allowNull: false,
field: "phoneNo"
},
emailId: {
type: DataTypes.STRING(20),
allowNull: false,
unique: true,
field: "emailId"
},
isActive: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: "0",
field: "isActive"
},
password: {
type: DataTypes.STRING(128),
allownull: false,
field: "password"
}
});
admin_users.associate = models => {
admin_users.hasMany(models.adminRole, {
foreignKey: "roleId"
});
};
return admin_users;
}
};
migration: mig-admin_user.js
"use strict";
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable("adminUser", {
id: {
type: Sequelize.INTEGER(22),
allowNull: false,
primaryKey: true,
autoIncrement: true,
field: "id"
},
fname: {
type: Sequelize.STRING(20),
allowNull: false,
field: "fname"
},
lname: {
type: Sequelize.STRING(20),
allowNull: true,
field: "lname"
},
phoneNo: {
type: Sequelize.STRING(20),
allowNull: false,
field: "phoneNo"
},
emailId: {
type: Sequelize.STRING(20),
allowNull: false,
unique: true,
field: "emailId"
},
isActive: {
type: Sequelize.BOOLEAN,
allowNull: false,
defaultValue: "0",
field: "isActive"
},
password: {
type: Sequelize.STRING(128),
allownull: false,
field: "password"
}
});
},
down: (queryInterface, Sequelize) => {
/*
Add reverting commands here.
Return a promise to correctly handle asynchronicity.
Example:
return queryInterface.dropTable('users');
*/
}
};
I tried looking for this particular error, but couldn't find anything.
could anyone please tell where i might be going wrong?
You need a .sequelizerc in the root of your project and it contains something like this :
module.exports = {
'config': 'database/config.js',
'migrations-path': 'database/migrations',
'seeders-path': 'database/seeders'
}
And you have to point where are your migrations been located.

Can i use `SET` variable in sequelize in nodejs

Can i use SET variable in sequelize in nodejs?
Sequelize
Model
Session Model
"use strict";
module.exports = (sequelize, DataTypes) => {
const Sessions = sequelize.define(
"sessions",
{
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
challenge_id: {
type: DataTypes.INTEGER,
references: {
model: "challenges",
key: "id"
},
allowNull: false
},
createdAt: { type: DataTypes.DATE },
createdBy: {
type: DataTypes.INTEGER,
references: {
model: "users",
key: "id"
},
allowNull: false
},
showAtLeaderboard: { type: DataTypes.ENUM("yes", "no") },
sessionFile: { type: DataTypes.STRING },
score: { type: DataTypes.INTEGER },
},
{
timestamps: false,
underscored: true
}
);
return Sessions;
};
Challenge Model
"use strict";
module.exports = (sequelize, DataTypes) => {
const Challenges = sequelize.define(
"challenges",
{
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
song_id: { type: DataTypes.INTEGER },
challenge_name: { type: DataTypes.STRING },
challengeDescription: { type: DataTypes.STRING },
challengeImg: { type: DataTypes.STRING },
challengeType: { type: DataTypes.STRING },
coins: { type: DataTypes.INTEGER },
createdAt: { type: DataTypes.DATE },
expireAt: { type: DataTypes.DATE },
isActive: { type: DataTypes.ENUM("yes", "no") },
tags: { type: DataTypes.STRING }
},
{
timestamps: false,
underscored: true
}
);
return Challenges;
};
Relationship
db.challenges.hasMany(db.sessions, {
foreignKey: "challenge_id",
sourceKey: "id"
});
Can I perform below SQL query with sequelize Orm model?
SET #rank=0
SELECT `challenges`.`*`, `sessions`.*, #rank:=#rank+1 AS rank FROM `challenges` JOIN `sessions` ON `sessions`.`challenge_id` = `challenges`.`id` ORDER BY `sessions`.`score` DESC
Sequelize support this type of query with it's ORM Model.

How to define unique index on multiple columns in sequelize

How do I define a unique index on a combination of columns in sequelize. For example I want to add a unique index on user_id, count and name.
var Tag = sequelize.define('Tag', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true
},
user_id: {
type: DataTypes.INTEGER(11),
allowNull: false,
},
count: {
type: DataTypes.INTEGER(11),
allowNull: true
},
name: {
type: DataTypes.STRING,
allowNull: true,
})
You can refer to this doc http://docs.sequelizejs.com/en/latest/docs/models-definition/#indexes
You will need to change your definition like shown below and call sync
var Tag = sequelize.define('Tag', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true
},
user_id: {
type: DataTypes.INTEGER(11),
allowNull: false,
},
count: {
type: DataTypes.INTEGER(11),
allowNull: true
},
name: {
type: DataTypes.STRING,
allowNull: true,
}
},
{
indexes: [
{
unique: true,
fields: ['user_id', 'count', 'name']
}
]
});
I have same issue to applied composite unique constraint to multiple
columns but nothing work with Mysql, Sequelize(4.10.2) and NodeJs
8.9.4 finally I fixed through following code.
queryInterface.createTable('actions', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
system_id: {
type: Sequelize.STRING,
unique: 'actions_unique',
},
rule_id: {
type: Sequelize.STRING,
unique: 'actions_unique',
},
plan_id: {
type: Sequelize.INTEGER,
unique: 'actions_unique',
}
}, {
uniqueKeys: {
actions_unique: {
fields: ['system_id', 'rule_id', 'plan_id']
}
}
});
If the accepted one is not working then try the below code. It worked for me in my case rather the accepted one.
var Tag = sequelize.define('Tag', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true
},
user_id: {
type: DataTypes.INTEGER(11),
allowNull: false,
unique: 'uniqueTag',
},
count: {
type: DataTypes.INTEGER(11),
allowNull: true,
unique: 'uniqueTag',
},
name: {
type: DataTypes.STRING,
allowNull: true,
unique: 'uniqueTag',
}
});
I tried to create an index on a single column.
This worked for me. Hope this helps.
Model
module.exports = (sequelize, DataTypes) => {
const Tag = sequelize.define(
"Tag",
{
name: { type: DataTypes.STRING, unique: true },
nVideos: DataTypes.INTEGER
},
{
indexes: [
{
unique: true,
fields: ["name"]
}
]
}
);
return Tag;
};
Migration
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable(
"Tags",
{
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
type: Sequelize.STRING,
unique: "unique_tag"
},
nVideos: { type: Sequelize.INTEGER },
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
},
{
uniqueKeys: {
unique_tag: {
customIndex: true,
fields: ["name"]
}
}
}
);
},
down: queryInterface => {
return queryInterface.dropTable("Tags");
}
};
I prefer sequelize sync method with composite unique, If not passing indexes name u will get a error as below on adding many indexes in index array.
error: SequelizeDatabaseError: Identifier name 'LONG_NAME' is too long
module.exports = function (sequelize: any, DataTypes: any) {
return sequelize.define('muln_user_goals_transaction', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
autoIncrement: true,
primaryKey: true,
},
name: {
type: DataTypes.STRING(),
allowNull: false,
},
email: {
type: DataTypes.STRING(),
allowNull: false,
},
phone: {
type: DataTypes.STRING(),
allowNull: false,
},
amount: {
type: DataTypes.INTEGER(8),
allowNull: false
},
deleted: {
type: DataTypes.BOOLEAN,
defaultValue: false,
},
}, {
tableName: 'muln_user_goals_transaction',
timestamps: false,
indexes: [
{
name: 'unique_index',
unique: true,
fields: ['name', 'email', 'phone', 'amount', 'deleted']
}
],
defaultScope: {
where: {
deleted: false
}
}
});
};
Sequelize composite unique (manual)
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Model', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
fieldOne: {
type: Sequelize.INTEGER,
unique: 'uniqueTag',
allowNull: false,
references: {
model: 'Model1',
key: 'id'
},
onUpdate: 'cascade',
onDelete: 'cascade'
},
fieldsTwo: {
type: Sequelize.INTEGER,
unique: 'uniqueTag',
allowNull: false,
references: {
model: 'Model2',
key: 'id'
},
onUpdate: 'cascade',
onDelete: 'cascade'
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
})
.then(function() {
return queryInterface.sequelize.query(
'ALTER TABLE `UserFriends` ADD UNIQUE `unique_index`(`fieldOne`, `fieldTwo`)'
);
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Model');
}
};