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

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 ?

Related

How to define in my model an array of id from another table in mysql and sequelize

I create an api in express.js, node.js, mysql and sequelize.
I have two models : Custom fields and Customer Types
Here is my customer type model :
module.exports = (sequelize, DataTypes) => {
const CustomerType = sequelize.define("customerType", {
name: {
type: DataTypes.STRING,
allowNull: false
},
description: {
type: DataTypes.STRING,
allowNull: false
},
user_id: {
type: DataTypes.STRING,
allowNull: false
}
})
return CustomerType
}
And there is my custom fields model :
const customerType = require('./customerTypeModel')
module.exports = (sequelize, DataTypes) => {
const CustomField = sequelize.define("customField", {
customer_type_ids: [
{
type: DataTypes.INTEGER,
references: {
model: customerType,
key: "id"
}
}
],
user_id: {
type: DataTypes.STRING,
allowNull: false
},
system_name: {
type: DataTypes.STRING,
allowNull: true
},
title: {
type: DataTypes.STRING,
allowNull: true
},
type: {
type: DataTypes.STRING,
allowNull: true
},
required: {
type: DataTypes.BOOLEAN,
allowNull: true
},
})
return CustomField
}
I need to have in my customField table an array of id from the customerType table.
For exemple i need to get a json like this :
{
"id": 1
"customer_types_ids": [
{
"id": 1,
"name": "Customers",
"description": "Customers",
"user_id": "123456"
},
{
"id": 2,
"name": "Leads",
"description": "Leads",
"user_id": "123456"
}
],
"user_id": "123456",
"system_name": "firstname",
"title": "Firstname",
"type": "text",
"required": true
}
How should I structure my custom field Model to be able to have a json like this in return?
Thanks for your help !
I assume you're expecting a One-to-Many relationship between CustomField and CustomerType. In this case, CustomerType owns the relation, so there is a reference to CustomField in the relational table of CustomerType called customFieldId.
// customerType.js
module.exports = (sequelize, DataTypes) => {
const CustomerType = sequelize.define("customerType", {
name: {
type: DataTypes.STRING,
allowNull: false
},
description: {
type: DataTypes.STRING,
allowNull: false
},
user_id: {
type: DataTypes.STRING,
allowNull: false
}
});
return CustomerType;
}
// customField.js
module.exports = (sequelize, DataTypes) => {
const CustomField = sequelize.define("customField", {
user_id: {
type: DataTypes.STRING,
allowNull: false
},
system_name: {
type: DataTypes.STRING,
allowNull: true
},
title: {
type: DataTypes.STRING,
allowNull: true
},
type: {
type: DataTypes.STRING,
allowNull: true
},
required: {
type: DataTypes.BOOLEAN,
allowNull: true
},
});
return CustomField;
}
// db.js
...
const CustomerType = require("./customerType.js")(sequelize, Sequelize.DataTypes);
const CustomField = require("./customField.js")(sequelize, Sequelize.DataTypes);
CustomField.hasMany(CustomerType, { as: "customer_types_ids" });
CustomerType.belongsTo(CustomField, {
foreignKey: "id",
as: "customFieldId",
});
This should define two relational tables with a One-to-Many relationship. The following code can be used to load a CustomField with all its CustomerTypes.
CustomField.findByPk(id, { include: ["customer_types_ids"] });

Sequelize Eager Loading Error: social_logins not associated to users

Users Model defined like this.
const db = require ('../../config/db_config');
const users = db.sequelize.define('users', {
id: {
type: db.DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
first_name: {
type: db.DataTypes.STRING(150),
},
last_name: {
type: db.DataTypes.STRING(150),
},
email: {
type: db.DataTypes.STRING(256),
required: true,
unique: true
},
password: {
type: db.DataTypes.STRING,
},
student_id: {
type: db.DataTypes.STRING
},
status: {
type: db.DataTypes.BOOLEAN,
required: true,
defaultValue: 0
},
is_deleted: {
type: db.DataTypes.BOOLEAN,
required: true,
defaultValue: 0
},
createdAt: db.DataTypes.DATE,
updatedAt: db.DataTypes.DATE,
});
module.exports = users;
social_logins Model defined like this
const db = require ('../../config/db_config');
const socialLogins = db.sequelize.define('social_logins', {
id: {
type: db.DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
token: {
type: db.DataTypes.STRING
},
tokenType: {
type: db.DataTypes.STRING
},
fb_id: {
type: db.DataTypes.STRING
},
user_id: {
type: db.DataTypes.INTEGER
},
is_deleted: {
type: db.DataTypes.BOOLEAN,
required: true,
defaultValue: false
}
}, { underscored: true, timestamp: true, tableName: 'social_logins' });
module.exports = socialLogins;
User model associated with the social_logins model using belongsTo function
socialLoginsModel.belongsTo(users)
Sequelize throws eagerLoadingError
Error EagerLoadingError [SequelizeEagerLoadingError]: social_logins is
not associated to users!
While running this query given below.
const userModel = require ('./users_model');
const socialLoginModel = require('../social_logins/social_logins_model');
let id = "123456";
let email = "ex#example.com";
userModel.findOne({
where: { email },
include: [{
model: socialLogins,
where: {
fb_id: id
}
}]
});
you should have associations like this based on your model names
socialLogins.belongsTo(users) & users.hasOne(socialLogins)/ users.hasMany(socialLogins) based on your relations being defined in DB

SequelizeEagerLoadingError: product is not associated to collection

I use sequelize ORM in Mysql. I have 3 Models: Product, Collection, CollectionProduct
relationship between Product and Collection are many to many and for handle this in sequelize i used belongsToMany association. every thing is Ok but when i run this code to get a collection with its products with include Eager this error occure:
SequelizeEagerLoadingError: product is not associated to collection!
Product Model:
module.exports = (sequelize, Sequelize) => {
const Product = sequelize.define('product', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
},
name_en: {
type: Sequelize.STRING(255),
},
description_en: {
type: Sequelize.STRING(1024),
},
price: {
type: Sequelize.FLOAT,
allowNull: false,
},
type: {
type: Sequelize.STRING(255),
},
height: {
type: Sequelize.INTEGER,
},
width: {
type: Sequelize.INTEGER,
},
createdAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
allowNull: false,
},
updatedAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
allowNull: false,
},
}, {})
Product.associate = (models) => {
Product.belongsToMany(models.collection, { through: models.collectionProduct, as: 'collections', foreignKey: 'productId' })
}
return Product
}
Collection Model :
module.exports = (sequelize, Sequelize) => {
const Collection = sequelize.define(
'collection', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
allowNull: false,
autoIncrement: true,
},
name_en: {
type: Sequelize.STRING(255),
},
itemsCount: {
type: Sequelize.INTEGER,
},
createdAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
allowNull: false,
},
updatedAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
allowNull: false,
},
}, {},
)
Collection.associate = (models) => {
Collection.belongsToMany(models.product, { through: models.collectionProduct, as: 'products', foreignKey: 'collectionId' })
}
return Collection
}
CollectionProduct Model:
module.exports = (sequelize, Sequelize) => {
const CollectionProduct = sequelize.define('collectionProduct', {
collectionId: {
type: Sequelize.INTEGER,
},
productId: {
type: Sequelize.INTEGER,
},
createdAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
allowNull: false,
},
updatedAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
allowNull: false,
},
}, {})
CollectionProduct.associate = (models) => {}
return CollectionProduct
}
routes/collection.js
const express = require('express')
const router = express.Router()
const Collection = require('../../controllers/collectionController')
router.get('/:id', async (req, res) => {
const { id: collectionId } = req.params
const collection = await Collection.getOne(collectionId)
return collection
}
collectionController
const db = require('../models/index')
const Collection = db.collection
const Product = db.product
const getOne = async (collectionId) => {
const collection = await Collection.findByPk(collectionId, {
include: {
model: Product,
as: 'products',
attributes: ['id', 'name_en'],
},
})
return collection
}
I found my problem. in collectionController i used model: Product
and Product should be a sequelize model. but in my code this is a function that have been called in models/index. so i changed my calling and pass a sequelize model to getOne

How to populate table with foreign key values, using sequelize?

I have models: Business, Contributor, Feedback.
I have created relationship between Feedback and Contributor, and Feedback and Business like this:
Feedback.belongsTo(Business)
Feedback.belongsTo(Contributor)
The corresponding foreign key attributes are added to the table Feedback. Question is, how to populate them with IDs coming from Business and Contributor table records?
This approach only gets the first record. If I use findAll(), then I get undefined.
for (let assetsUrl of assetUrls) {
...
var businesses = null;
var reviews = null;
...
var timestamp = Math.floor(Date.now() / 1000);
var b_id = await Business.findOne({
attributes: ["id"],
})
var c_id = await Contributor.findOne({
})
businesses = await Business.upsert({
...
last_scraped: timestamp
});
reviews = await Review.upsert(
{
contributor_id: c_id.id,
business_id: b_id.id,
last_scraped: timestamp,
},
)
}
Business model:
class Business extends Model {}
Business.init(
{
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
},
site: {
type: Sequelize.STRING,
},
name: {
type: Sequelize.STRING,
},
business_type: {
type: Sequelize.STRING,
unique: false,
defaultValue: "",
},
address: {
type: Sequelize.TEXT,
// allowNull defaults to true
},
price: {
type: Sequelize.STRING,
},
url: {
type: Sequelize.STRING,
allowNull: false,
unique: true,
},
last_scraped: {
type: Sequelize.INTEGER,
defaultValue: Math.floor(Date.now() / 1000)
},
},
{
sequelize,
modelName: "business",
timestamps: true,
createdAt: false,
updatedAt: false,
underscored: true
}
);
Business === sequelize.models.Business;
Business.sync();
Contributor model:
class Contributor extends Model {}
Contributor.init(
{
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
},
site: {
type: Sequelize.STRING,
},
name: {
type: Sequelize.STRING,
unique: false,
},
location: {
type: Sequelize.STRING,
unique: false,
},
photo: {
type: Sequelize.STRING,
unique: false,
},
url: {
type: Sequelize.STRING,
allowNull: false,
unique: true,
},
status: {
type: Sequelize.SMALLINT,
},
last_scraped: {
type: Sequelize.INTEGER,
defaultValue: Math.floor(Date.now() / 1000)
},
},
{
sequelize,
modelName: "contributor",
timestamps: true,
createdAt: false,
updatedAt: false,
underscored: true,
}
);
Contributor === sequelize.models.Contributor;
Contributor.sync();
Feedback model:
class Feedback extends Model {}
Feedback.init(
{
contributor_id: {
type: Sequelize.INTEGER,
},
business_id: {
type: Sequelize.INTEGER,
},
date: {
type: Sequelize.STRING,
unique: false,
},
rating: {
type: Sequelize.STRING,
unique: false,
},
content: {
type: Sequelize.STRING,
unique: false,
},
last_scraped: {
type: Sequelize.INTEGER,
defaultValue: Math.floor(Date.now() / 1000)
},
},
{
sequelize,
modelName: "feedback",
timestamps: true,
createdAt: false,
updatedAt: false,
underscored: true,
}
);
Feedback.belongsTo(Contributor, { foreignKey: 'contributor_id' })
Feedback.belongsTo(Business, { foreignKey: 'business_id'})
Feedback=== sequelize.models.Review;
Feedback.sync();
A Good use case for model streaming but I think sequelize doesn't
support it yet
With your approch, using findOne combined with offset option you can
create/update the Feedback model like this.
// Get number of records to avoid unnecessary findOne in the loop
const bRecordCount = await Business.count();
const cRecordCount = await Contributor.count();
for (let i = 0; i < assetUrls.length; i++) {
const assetsUrl = assetUrls[i];
// ...
let bRecord = null;
let cRecord = null;
let options = {
attributes: ["id"],
// order by id to be sure we get different record each time
order: [['id', 'ASC']],
raw: true,
offset: i //skip already taken records
};
try {
if (i < bRecordCount && i < cRecordCount) {
bRecord = await Business.findOne(options)
cRecord = await Contributor.findOne(options)
}
if (bRecord && cRecord) {
feedback = await Feedback.upsert({
contributor_id: cRecord.id,
business_id: bRecord.id,
last_scraped: timestamp,
//...
});
}
} catch (err) {
console.log(err);
}
}
If you have many records you should consider using
findAll()
with offset and limit options,
then do a bulkCreate()
with updateOnDuplicate option to avoid making many database queries
To get Feedback items with certain attributes call findAll:
var feedback = await Feedback.findAll({
attributes: ['contributor_id', 'business_id', 'last_scraped']
})

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.