Node.js Sequelize virtual column pulling value from other model - mysql

I'm working with Sequelize 5.7, trying to utilize virtual datatype,
to pull related information into a model.
Given simplified company and user models, how do I get company.name
into user.companyname ?
company
let Schema = sequelize.define(
"company",
{
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true
},
name: {
type: DataTypes.STRING(45)
}
}
);
user
let Schema = sequelize.define(
"user",
{
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true
},
login: {
type: DataTypes.STRING(45),
unique: true
},
company: {
type: DataTypes.INTEGER.UNSIGNED,
references: {
model: sequelize.model('company'),
key: 'id'
}
},
/* This companyname contruct is pure fantasy, and the target of my question */
companyname: {
type: new DataTypes.VIRTUAL(DataTypes.STRING,['company']),
references: {
model: 'company',
key: 'name'
}
}
}
);

In your case, I think it is a better idea to use a relationship (an association)
Sequelize Associations
const User = sequelize.define('user', {
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true
},
login: {
type: DataTypes.STRING(45),
unique: true
},
company_id: {
type: DataTypes.INTEGER.UNSIGNED,
},
});
const Company = sequelize.define('company', {
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true,
},
name: {
type: DataTypes.STRING,
},
});
User.belongsTo(Company, {
foreignKey: 'company_id', // you can use this to customize the fk, default would be like companyId
});
Company.hasMany(User);
Then when calling your model you do something like:
User.findAll({ include: Company }).then(users => console.log(users));

I solved the problem by using type: DataTypes.VIRTUAL in model
const { Model, DataTypes } = require('sequelize');
class User extends Model {
static init(sequelize) {
super.init({
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true
},
login: {
type: DataTypes.STRING(45),
unique: true
},
company_id: {
type: DataTypes.INTEGER.UNSIGNED,
},
companyname:{
type: DataTypes.VIRTUAL,
get() {
return this.Company?.get().name;
},
set(/*value*/) {
throw new Error('Do not try to set the `companyname` value!');
}
},
}, {
sequelize
})
}
static associate(models) {
this.belongsTo(Company, {
foreignKey: 'company_id',
});
}
}
module.exports = User;
to search just include the association :
User.findAll({ include: Company })
I usually create each model using 'class' in different files, but if you need, just include the code below in the #jalex19 solution
companyname:{
type: DataTypes.VIRTUAL,
get() {
return this.Company?.get().name;
},
set(/*value*/) {
throw new Error('Do not try to set the `fullName` value!');
}
},

Related

Sequelize seems to ignore associations with natural keys and/or adds additional fields

I have 2 situations. The main thing that connects them is that the primary keys on the tables are not autoincrement integers, which seems to cause sequelize to try to create additional association or field names.
Situation 1, I have 2 tables, I have the associations defined. When I try to query it, a random extra field gets inserted, throwing an error.
Model 1 file
const { DataTypes, Model } = require('sequelize');
const modelName = 'BusinessAccountSetting';
const tableName = 'BusinessAccountSettings';
class BusinessAccountSetting extends Model {
static doInit (sequelize) {
this.init({
_id: {
type: DataTypes.BIGINT.UNSIGNED,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
BusinessAccountId: {
type: DataTypes.INTEGER.UNSIGNED,
allowNull: false
},
BusinessSettingKey: {
type: DataTypes.STRING(200),
allowNull: false,
defaultValue: true
},
value: {
type: DataTypes.JSON,
allowNull: false
}
}, {
sequelize,
modelName,
tableName,
timestamps: true,
paranoid: true
});
};
static associate (models) {
this.belongsTo(models.BusinessAccount, {
as: 'business',
foreignKey: 'BusinessAccountId',
targetKey: '_id'
});
this.belongsTo(models.BusinessSetting, {
as: 'setting',
foreignKey: 'BusinessSettingKey',
targetKey: 'BusinessSettingKey'
});
};
};
module.exports = {
modelName,
model: BusinessAccountSetting
};
Model 2 file
const { DataTypes, Model } = require('sequelize');
const modelName = 'BusinessSetting';
const tableName = 'BusinessSettings';
class BusinessSetting extends Model {
static doInit (sequelize) {
this.init({
BusinessSettingKey: {
type: DataTypes.STRING(200),
allowNull: false,
primaryKey: true,
unique: true
},
label: {
type: DataTypes.STRING(200),
allowNull: false
},
description: {
type: DataTypes.STRING(500),
allowNull: true
},
defaultValue: {
type: DataTypes.JSON,
allowNull: false
},
BusinessSettingGroupKey: {
type: DataTypes.STRING(200),
allowNull: false
},
order: {
type: DataTypes.SMALLINT.UNSIGNED,
allowNull: false
}
}, {
sequelize,
modelName,
tableName,
timestamps: true,
paranoid: true
});
};
static associate (models) {
this.belongsTo(models.BusinessSettingGroup, {
as: 'group',
foreignKey: 'BusinessSettingGroupKey',
targetKey: 'BusinessSettingGroupKey'
});
this.hasMany(models.BusinessAccountSetting, {
as: 'businessAccountSettings',
foreignKey: 'BusinessSettingKey',
sourceKey: 'BusinessSettingKey'
});
};
};
module.exports = {
modelName,
model: BusinessSetting
};
When I run this query
const settings = await sqldb.BusinessSetting.findAll({
include: [
{
model: sqldb.BusinessAccountSetting,
as: 'businessAccountSettings',
where: {
BusinessAccountId
},
required: false
}
]
});
It generates this sql
SELECT
`BusinessSetting`.`BusinessSettingKey`,
`BusinessSetting`.`label`,
`BusinessSetting`.`description`,
`BusinessSetting`.`defaultValue`,
`BusinessSetting`.`BusinessSettingGroupKey`,
`BusinessSetting`.`order`,
`BusinessSetting`.`createdAt`,
`BusinessSetting`.`updatedAt`,
`BusinessSetting`.`deletedAt`,
`businessAccountSettings`.`_id` AS `businessAccountSettings._id`,
`businessAccountSettings`.`BusinessAccountId` AS `businessAccountSettings.BusinessAccountId`,
`businessAccountSettings`.`BusinessSettingKey` AS `businessAccountSettings.BusinessSettingKey`,
`businessAccountSettings`.`value` AS `businessAccountSettings.value`,
`businessAccountSettings`.`createdAt` AS `businessAccountSettings.createdAt`,
`businessAccountSettings`.`updatedAt` AS `businessAccountSettings.updatedAt`,
`businessAccountSettings`.`deletedAt` AS `businessAccountSettings.deletedAt`,
`businessAccountSettings`.`BusinessSettingBusinessSettingKey` AS `businessAccountSettings.BusinessSettingBusinessSettingKey`
FROM
`BusinessSettings` AS `BusinessSetting` LEFT OUTER JOIN `BusinessAccountSettings` AS `businessAccountSettings` ON `BusinessSetting`.`BusinessSettingKey` = `businessAccountSettings`.`BusinessSettingKey`
AND (`businessAccountSettings`.`deletedAt` IS NULL AND `businessAccountSettings`.`BusinessAccountId` = 20)
WHERE (`BusinessSetting`.`deletedAt` IS NULL);
Which throws an error because of this:
`businessAccountSettings`.`BusinessSettingBusinessSettingKey` AS `businessAccountSettings.BusinessSettingBusinessSettingKey`
The associations are defined. The primary keys are defined. It should not be trying to add additional fields to fill in the blanks.
It's not an extra hook because it is trying to create a field for the reverse association which is already defined. It's not coming from another model association and I went through all of my files and remove the hooks: true flags just to be sure.
Problem #2, M:N associations with non-numeric keys
File #1
const { DataTypes, Model } = require('sequelize');
const modelName = 'BusinessRoleTemplate';
const tableName = 'BusinessRoleTemplates';
class BusinessRoleTemplate extends Model {
static doInit (sequelize) {
this.init({
BusinessRoleTemplateKey: {
type: DataTypes.STRING(100),
primaryKey: true,
allowNull: false,
unique: true
},
description: {
type: DataTypes.STRING(250),
allowNull: true
},
group: {
type: DataTypes.STRING(50),
allowNull: true
},
isCategoryTemplate: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false
},
ranking: {
type: DataTypes.TINYINT.UNSIGNED,
allowNull: false
},
active: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: true
}
}, {
sequelize,
modelName,
tableName,
timestamps: true,
paranoid: true
});
};
static associate (models) {
this.belongsToMany(models.BusinessPermission, {
as: 'permissions',
through: models.BusinessRoleTemplatePermission
});
};
};
module.exports = {
modelName,
model: BusinessRoleTemplate
};
File 2
const { DataTypes, Model } = require('sequelize');
const modelName = 'BusinessPermission';
const tableName = 'BusinessPermissions';
class BusinessPermission extends Model {
static doInit (sequelize) {
this.init({
BusinessPermissionKey: {
type: DataTypes.STRING(100),
allowNull: false,
primaryKey: true,
unique: true
},
plainText: {
type: DataTypes.STRING(100),
allowNull: false
},
description: {
type: DataTypes.STRING(250),
allowNull: true
},
requiresRank: {
type: DataTypes.INTEGER(2).UNSIGNED,
allowNull: false,
defaultValue: 10
},
BusinessPermissionGroupKey: {
type: DataTypes.STRING(100),
allowNull: false
},
isCategoryPermission: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false
},
active: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: true
}
}, {
sequelize,
modelName,
tableName,
timestamps: true,
paranoid: true
});
};
static associate (models) {
this.belongsTo(models.BusinessPermissionGroup, {
as: 'group',
foreignKey: 'BusinessPermissionGroupKey',
targetKey: 'BusinessPermissionGroupKey'
});
this.hasMany(models.BusinessPermissionAlternative, {
as: 'alternates',
foreignKey: 'AlternateBusinessPermissionKey',
sourceKey: 'BusinessPermissionKey'
});
this.belongsToMany(models.BusinessRoleTemplate, {
as: 'roleTemplates',
through: models.BusinessRoleTemplatePermission
});
this.belongsToMany(models.BusinessRole, {
as: 'roles',
through: models.BusinessRolePermission
});
};
};
module.exports = {
modelName,
model: BusinessPermission
};
Association table
const { DataTypes, Model } = require('sequelize');
const modelName = 'BusinessRoleTemplatePermission';
const tableName = 'BusinessRoleTemplatePermissions';
class BusinessRoleTemplatePermission extends Model {
static doInit (sequelize) {
this.init({
_id: {
type: DataTypes.INTEGER.UNSIGNED,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
BusinessPermissionKey: {
type: DataTypes.STRING(100),
allowNull: false
},
BusinessRoleTemplateKey: {
type: DataTypes.STRING(100),
allowNull: false
}
}, {
sequelize,
modelName,
tableName,
timestamps: true,
paranoid: false
});
};
static associate (models) {
this.belongsTo(models.BusinessPermission, {
as: 'permission',
foreignKey: 'BusinessPermissionKey',
targetKey: 'BusinessPermissionKey'
});
this.belongsTo(models.BusinessRoleTemplate, {
as: 'role',
foreignKey: 'BusinessRoleTemplateKey',
targetKey: 'BusinessRoleTemplateKey'
});
};
};
module.exports = {
modelName,
model: BusinessRoleTemplatePermission
};
BusinessRoleTemplate hasMany BusinessPermissions through BusinessRoleTemplatePermissions
BusinessRoleTemplatePermissions has the associations for both tables defined, so there shouldn't be a need for anything else.
However, when I run this query:
role = await sqldb.BusinessRoleTemplate.findOne({
where: {
BusinessRoleTemplateKey: data.role
},
attributes: ['BusinessRoleTemplateKey', 'description', 'isCategoryTemplate', 'ranking'],
include: [
{
model: sqldb.BusinessPermission,
as: 'permissions',
attributes: ['BusinessPermissionKey', 'isCategoryPermission']
}
]
});
I get this SQL:
SELECT
`BusinessRoleTemplate`.`BusinessRoleTemplateKey`,
`BusinessRoleTemplate`.`description`,
`BusinessRoleTemplate`.`isCategoryTemplate`,
`BusinessRoleTemplate`.`ranking`,
`permissions`.`BusinessPermissionKey` AS `permissions.BusinessPermissionKey`,
`permissions`.`isCategoryPermission` AS `permissions.isCategoryPermission`,
`permissions->BusinessRoleTemplatePermission`.`_id` AS `permissions.BusinessRoleTemplatePermission._id`,
`permissions->BusinessRoleTemplatePermission`.`BusinessPermissionKey` AS `permissions.BusinessRoleTemplatePermission.BusinessPermissionKey`,
`permissions->BusinessRoleTemplatePermission`.`BusinessRoleTemplateKey` AS `permissions.BusinessRoleTemplatePermission.BusinessRoleTemplateKey`,
`permissions->BusinessRoleTemplatePermission`.`createdAt` AS `permissions.BusinessRoleTemplatePermission.createdAt`,
`permissions->BusinessRoleTemplatePermission`.`updatedAt` AS `permissions.BusinessRoleTemplatePermission.updatedAt`,
`permissions->BusinessRoleTemplatePermission`.`BusinessPermissionBusinessPermissionKey` AS `permissions.BusinessRoleTemplatePermission.BusinessPermissionBusinessPermissionKey`,
`permissions->BusinessRoleTemplatePermission`.`BusinessRoleTemplateBusinessRoleTemplateKey` AS `permissions.BusinessRoleTemplatePermission.BusinessRoleTemplateBusinessRoleTemplateKey`
FROM `BusinessRoleTemplates` AS `BusinessRoleTemplate`
LEFT OUTER JOIN (
`BusinessRoleTemplatePermissions` AS `permissions->BusinessRoleTemplatePermission`
INNER JOIN `BusinessPermissions` AS `permissions`
ON `permissions`.`BusinessPermissionKey` = `permissions->BusinessRoleTemplatePermission`.`BusinessPermissionBusinessPermissionKey`)
ON `BusinessRoleTemplate`.`BusinessRoleTemplateKey` = `permissions->BusinessRoleTemplatePermission`.`BusinessRoleTemplateBusinessRoleTemplateKey`
AND (`permissions`.`deletedAt` IS NULL)
WHERE (`BusinessRoleTemplate`.`deletedAt` IS NULL AND `BusinessRoleTemplate`.`BusinessRoleTemplateKey` = 'Senior Manager');
With all sorts of stuff added:
added fields:
`permissions->BusinessRoleTemplatePermission`.`BusinessPermissionBusinessPermissionKey` AS `permissions.BusinessRoleTemplatePermission.BusinessPermissionBusinessPermissionKey`,
`permissions->BusinessRoleTemplatePermission`.`BusinessRoleTemplateBusinessRoleTemplateKey` AS `permissions.BusinessRoleTemplatePermission.BusinessRoleTemplateBusinessRoleTemplateKey`
Added associations:
ON `permissions`.`BusinessPermissionKey` = `permissions->BusinessRoleTemplatePermission`.`BusinessPermissionBusinessPermissionKey`)
If I change the association in BusinessRoleTemplate to this, it works:
this.belongsToMany(models.BusinessPermission, {
as: 'permissions',
through: models.BusinessRoleTemplatePermission,
foreignKey: 'BusinessRoleTemplateKey',
otherKey: 'BusinessPermissionKey'
});
I shouldn't need to add the foreignKey and otherKey because the associations are already defined in the through table, but sequelize isn't recognizing them, it is trying to create them.

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 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

date_format with sequelize mysql

I am using sequelize for my backend and I want to add a where condition with YYYY-mm-dd
In mysql we use date_format(dateCreated, "%d-%m-%Y").
But how to achieve it in Sequelize. I searched all over the google but nothing helped me out
My present Sequelize query. I want to get data of dateCreated = '2020-05-31'.
const apartmentOrdersData = await apartments_order.findAll(
{
where: { apid: req.body.apid }, group: ['apcid'],
attributes: ['apcid', [sequelize.fn('sum', sequelize.col('totalCost')), 'total_amount'],],
include: [apartments_child]
});
My model:
const { DataTypes, Model } = require('sequelize');
const sequelize = require('../../../mysql_connection/sequilize');
const admins = require('./admins');
const apartments_child = require('./apartments_child');
class apartments_order extends Model { }
apartments_order.init({
// Model attributes are defined here
apoid: {
type: DataTypes.INTEGER,
primaryKey: true
},
invoiceNo: {
type: DataTypes.STRING
},
apid: {
type: DataTypes.INTEGER
},
apcid: {
type: DataTypes.INTEGER
},
apcbid: {
type: DataTypes.INTEGER
},
totalCost: {
type: DataTypes.DECIMAL
},
dateCreated: {
type: DataTypes.DATE
},
dateUpdated: {
type: DataTypes.DATE
},
createdBy: {
type: DataTypes.STRING
},
updatedBy: {
type: DataTypes.STRING
},
status: {
type: DataTypes.STRING
}
}, {
sequelize,
timestamps: false,
logging: false,
tableName: 'apartments_order'
});
apartments_order.hasOne(admins, { foreignKey: 'aid', sourceKey: 'createdBy' });
apartments_order.hasOne(apartments_child, { foreignKey: 'apcid', sourceKey: 'apcid' });
module.exports = apartments_order;
One thing that you can do is use a setter and getter for the columns.
Follow an example (on your field declaration, you can manipulate the data inside getter() and setter():
dateUpdated: {
type: Sequelize.STRING,
defaultValue: '[]',
get() {
const d = this.getDataValue('dateUpdated');
return format(d, 'Y-m-d');
},
set(value) {
return this.setDataValue('dateUpdated', format(value, <your-format-here>)
},
type: DataTypes.DATE,
},

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']
})