nodejs sequelize join 2 table using hasmany - node.js

I am new in nodejs. I am creating new app using nodejs. i want to join two table city and state using hasmany relations.
Here is my state model state.js
module.exports = function(sequelize, DataTypes) {
return sequelize.define('state', {
name: {
type: DataTypes.STRING(255),
allowNull: true
},
id: {
type: DataTypes.INTEGER(10).UNSIGNED,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
createdAt: {
type: DataTypes.DATE,
allowNull: true
},
updatedAt: {
type: DataTypes.DATE,
allowNull: true
}
}, {
tableName: 'state'
});
};
Here is my city model city.js
module.exports = function(sequelize, DataTypes) {
return sequelize.define('city', {
state: {
type: DataTypes.INTEGER(11),
allowNull: true
},
name: {
type: DataTypes.STRING(255),
allowNull: true
},
id: {
type: DataTypes.INTEGER(10).UNSIGNED,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
createdAt: {
type: DataTypes.DATE,
allowNull: true
},
updatedAt: {
type: DataTypes.DATE,
allowNull: true
}
}, {
tableName: 'city'
});
};
This is my citycontroller.js
let City = require('../models').city;
let State = require('../models').state;
let message = require('../../config/message');
let Boom = require('boom');
module.exports = {
listCity: async(request,h) =>{
let stateid = request.query.stateid;
try{
let searchQuery = {};
if(stateid) searchQuery.state = stateid;
let listCity = await City.findAll({ where:searchQuery});
if(listCity.length){
let response = {
"statusCode": 200,
"message":message.DATAFOUND,
"result": listCity
};
return h.response(response).code(200);
}else{
return h.response(response).code(204);
}
}catch(err){
return Boom.badRequest(err.message);
}
},
};
Output:
{
"statusCode": 200,
"message": "Data found",
"result": [
{
"state": 1,
"name": "Los Angeles",
"id": 1,
"createdAt": null,
"updatedAt": null
},
{
"state": 1,
"name": "San Francisco",
"id": 2,
"createdAt": null,
"updatedAt": null
},
{
"state": 5,
"name": "Southhampton",
"id": 3,
"createdAt": null,
"updatedAt": null
}
]
}
Now it listing city details only. but i need to join state details also under each city.

If you want to select the data from the state table than define a relation in the state model.
module.exports = function(sequelize, DataTypes) {
const state = sequelize.define('state', {
name: {
type: DataTypes.STRING(255),
allowNull: true
},
id: {
type: DataTypes.INTEGER(10).UNSIGNED,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
createdAt: {
type: DataTypes.DATE,
allowNull: true
},
updatedAt: {
type: DataTypes.DATE,
allowNull: true
}
}, {
tableName: 'state'
});
state.associate = function(model){
models.state.hasMany(models.city){
foreignKey: 'state'
}
return state;
}
};
Or if you want to select data from the city table than define a similar hasOne relation in city table.

Related

Sequelize fetch include data based on alias where condition

I have two tables Employee and Department
Department
const Department = Sequelize.define(
"Department",
{
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
},
{
underscored: true,
timestamps: true,
paranoid: true,
modelName: "Department",
tableName: "departments",
},
);
Department.associate = function (models) {
// associations can be defined here
models.Department.hasMany(models.Employee, {
foreignKey: "department_id",
as: "employees",
});
};
return Department;
};
Employee
const Employee = Sequelize.define(
"Employee",
{
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
name: {
type: DataTypes.STRING,
unique: true,
allowNull: false,
},
status: {
type: DataTypes.STRING,
defaultValue: "active",
},
departmentId: {
type: DataTypes.INTEGER,
},
},
{
underscored: true,
timestamps: true,
modelName: "Employee",
tableName: "employees",
},
);
Employee.associate = function (models) {
models.Employee.belongsTo(models.Department, {
foreignKey: "department_id",
as: "department",
});
};
return Employee;
};
Now I have to fetch the list of employees and putting a filter of department_id = 1
const { departmentId } = req.body;
const employees = await Employee.findAll({
include: [
{
model: Department,
where: {
id: departmentId,
},
},
],
});
I am getting the issue. Department is mapped by association "departments"
Cannot fetch the data.
I found the answer on sequelize docs
const employees = await Employee.findAll({
include: [
{
association: "department", // this is the place to change
where: {
id: departmentId,
},
},
],
});
Learnings:
We will not be able to put association and model together.
We will be able to use the Model if no association is there.
We will be able to use association if there is one.
References: https://sequelize.org/master/manual/eager-loading.html#:~:text=You%20can%20also%20include%20by%20alias%20name%20by%20specifying%20a%20string%20that%20matches%20the%20association%20alias

Sequelize - Retrieve association after model creation

I am creating a model through a relation, I would like to know if it is possible to obtain the relation in the return of the model.
Company Model
module.exports = (sequelize) => {
const company = sequelize.define('company', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER
},
uuid: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4
},
name: {
type: DataTypes.STRING,
allowNull: false
}
})
company.hasMany(sequelize.models.flow, {foreignKey: 'company_id', as: 'flows'})
}
Flow model
module.exports = (sequelize) => {
const flow = sequelize.define('flow', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER
},
company_id: {
allowNull: false,
type: DataTypes.INTEGER
},
uuid: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4
},
name: {
type: DataTypes.STRING,
allowNull: false
},
description: {
type: DataTypes.TEXT
}
})
flow.belongsTo(sequelize.models.company, {foreignKey: 'company_id', as: 'company'})
}
Query
const company = await ORM.models.company
.findOne({
where: {
uuid: req.body.company_id
}
})
if (company) {
const flow = await company.createFlow({
name: req.body.name
})
return res.json(flow)
}
I am currently getting the following response:
{
"uuid": "647aa7b2-163a-4bab-80f6-441c9bf29915",
"id": 12,
"name": "Flow 2",
"company_id": 2,
"updated_at": "2021-02-11T06:08:25.160Z",
"created_at": "2021-02-11T06:08:25.160Z",
"description": null
}
I would like to obtain:
{
"uuid":"647aa7b2-163a-4bab-80f6-441c9bf29915",
"id":12,
"name":"Flow 2",
"updated_at":"2021-02-11T06:08:25.160Z",
"created_at":"2021-02-11T06:08:25.160Z",
"description":null,
"company":{
"id":2,
"uuid":"3dea2541-a505-4f0c-a356-f1a2d449d050",
"name":"Company 1",
"created_at":"2021-02-11T05:48:11.872Z",
"updated_at":"2021-02-11T05:48:11.872Z"
}
}
It is possible?
Because you are not attaching company data with the result JSON data structure, so you are getting only flow data.
To get the expected result please try to modify the JSON structure as follows:
flow.company = company;
just before the return res.json(flow).

findAll sequelize with model returning odd values

Solved thanks to : https://stackoverflow.com/a/64702949/14585149
I am looking to list all transactions I have on a mysql database with the associated users.
I have 2 tables / models : Transaction & User
Transaction :
module.exports = function(sequelize, DataTypes) {
return sequelize.define('transactions', {
transaction_id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true
},
user_id: {
type: DataTypes.INTEGER(11),
allowNull: false,
references: {
model: 'users',
key: 'user_id'
}
},
account_id: {
type: DataTypes.INTEGER(11),
allowNull: false,
references: {
model: 'accounts',
key: 'account_id'
}
},
}, { tableName: 'transactions' }); };
User :
module.exports = function(sequelize, DataTypes) {
return sequelize.define('users', {
user_id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
references: {
model: 'recipients',
key: 'created_by'
}
},
contact_id: {
type: DataTypes.INTEGER(11),
allowNull: true,
references: {
model: 'contacts',
key: 'contact_id'
}
}, }, {
tableName: 'users',
timestamps: false
});
};
I have made the associations :
Transaction.hasOne(User, {foreignKey:'user_id'});
User.belongsTo(Transaction, {foreignKey:'user_id'});
and my code is :
api.get('/trx', async (req, res) => {
Transaction.findAll({
attributes: ['transaction_id','user_id','account_id'],
include: [{
model: User,
attributes: ['user_id']}]
})
.then(intrx => res.json(intrx))
.catch(res.catch_error)
});
the result :
[
{
"transaction_id": 1,
"user_id": 4,
"account_id": 1,
"user": {
"user_id": 1
}
},
{
"transaction_id": 2,
"user_id": 4,
"account_id": 75,
"user": {
"user_id": 2
}
}
]
why the values of user_id are different ?
I am expecting the user_id = 4 instead of 1 in my first result and user_id = 4 in my second result.
what I am doing wrong ?
You should reverse your associations like this:
Transaction.belongsTo(User, {foreignKey:'user_id'});
User.hasOne(Transaction, {foreignKey:'user_id'});
because Transaction has link to User i.e. belongs to it.

How can I use current query value in sequelize?

I am new with sequelize and i need to include multiple table, i try belove:
const result = await product.findAll({
where: {
isDeleted: false,
sellerId
},
attributes: ["name", "type", "isActive", "subCategoryIds"],
include: [
{
model: category,
as: 'categories',
attributes: ["name"],
},
{
model: category,
as: 'subCategories',
attributes: ["name"],
where: {
id: _.split(sequelize.col("subCategoryIds"), ",")
},
},
],
offset: (page - 1) * limit,
limit
});
But it's return error :
SequelizeDatabaseError: operator does not exist: character varying = integer
Product model is:
const product = sequelize.define("products",
{
id: {
type: DataTypes.BIGINT.UNSIGNED,
field: "id",
primaryKey: true,
autoIncrement: true,
index: true,
},
name: {
type: DataTypes.STRING,
field: "name",
allowNull: false,
},
type: {
type: DataTypes.STRING,
field: "type",
allowNull: false,
},
categoryId: {
type: DataTypes.NUMBER,
field: "categoryId",
references: {
key: "id",
model: category,
},
allowNull: false,
},
sellerId: {
type: DataTypes.NUMBER,
field: "sellerId",
references: {
key: "id",
model: user,
},
allowNull: false,
},
subCategoryIds: {
type: DataTypes.STRING,
allowNull: false,
get() {
const result = _.split(this.getDataValue("subCategoryIds"), ",").map(item => +item);
return result;
}
},
isDeleted: {
type: DataTypes.BOOLEAN,
field: "isDeleted",
defaultValue: false,
},
createdAt: {
type: DataTypes.DATE,
field: "createdAt",
defaultValue: DataTypes.NOW,
},
updatedAt: {
type: DataTypes.DATE,
field: "updatedAt",
defaultValue: DataTypes.NOW,
}
}, {
tableName: "products",
timestamps: false
}
);
product.belongsTo(category, { as: "categories", foreignKey: 'categoryId' });
category.hasMany(product, { as: "products", foreignKey: 'categoryId' });
product.belongsTo(category, { as: "subCategories", foreignKey: 'subCategoryIds' });
I am not getting what's going wrong
is there any solution for this
details in table like
categoryId => 11 subCategoryIds => 11, 12
if i remove
{
model: category,
as: 'subCategories',
attributes: ["name"],
where: {
id: _.split(sequelize.col("subCategoryIds"), ",")
},
},
then it's working fine, problem is sequelize.col("subCategoryIds") return string col("subCategoryIds") not the actual value of the subCategories ids 11, 12

findAll doesn't get object structure according to Includes Sequelize

I have tables like Medics, MedicalSpecialties and Users. Models are define like:
Users Model
const Database = require('../sequelize');
const UserModel = Database
.getInstance()
.define('users', {
UserId: {
type: Database.FIELD_TYPE_ENUM.INTEGER,
primaryKey: true,
autoIncrement: true
},
FirstName: Database.FIELD_TYPE_ENUM.STRING,
MiddleName: Database.FIELD_TYPE_ENUM.STRING,
LastName: Database.FIELD_TYPE_ENUM.STRING,
SecondLastName: Database.FIELD_TYPE_ENUM.STRING,
ID: Database.FIELD_TYPE_ENUM.STRING,
Email: Database.FIELD_TYPE_ENUM.STRING,
Password: Database.FIELD_TYPE_ENUM.STRING,
CellPhoneNumber: Database.FIELD_TYPE_ENUM.STRING,
OtherPhoneNumber: Database.FIELD_TYPE_ENUM.STRING,
Deleted: Database.FIELD_TYPE_ENUM.BOOLEAN
});
module.exports = UserModel;
Medical Specialties Model
const Database = require('../sequelize');
const MedicalSpecialtyModel = Database
.getInstance()
.define('medicalspecialties', {
MedicalSpecialtyId: {
type: Database.FIELD_TYPE_ENUM.INTEGER,
primaryKey: true,
autoIncrement: true
},
Description: Database.FIELD_TYPE_ENUM.STRING,
CreatedUserId: {
type: Database.FIELD_TYPE_ENUM.INTEGER,
references: {
model: 'users',
key: 'UserId'
}
},
UpdatedUserId: {
type: Database.FIELD_TYPE_ENUM.INTEGER,
references: {
model: 'users',
key: 'UserId'
},
allowNull: true
},
createdAt: Database.FIELD_TYPE_ENUM.DATETIME,
updatedAt: Database.FIELD_TYPE_ENUM.DATETIME
});
module.exports = MedicalSpecialtyModel;
Medics Model
const Database = require('../sequelize');
const MedicModel = Database
.getInstance()
.define('medics', {
MedicId: {
type: Database.FIELD_TYPE_ENUM.INTEGER,
primaryKey: true,
autoIncrement: true
},
UserId: {
type: Database.FIELD_TYPE_ENUM.INTEGER,
primaryKey: true,
autoIncrement: false,
references: {
model: 'users',
key: 'UserId'
}
},
MedicalSpecialtyId: {
type: Database.FIELD_TYPE_ENUM.INTEGER,
references: {
model: 'medicalspecialties',
key: 'MedicalSpecialtyId'
}
},
Code: Database.FIELD_TYPE_ENUM.STRING,
CreatedUserId: {
type: Database.FIELD_TYPE_ENUM.INTEGER,
references: {
model: 'users',
key: 'UserId'
}
},
UpdatedUserId: {
type: Database.FIELD_TYPE_ENUM.INTEGER,
references: {
model: 'users',
key: 'UserId'
},
allowNull: true
}
});
module.exports = MedicModel;
What I want to do is to get results with object parent child Representation like
[
{
"MedicId": 1,
"Code": "test1",
"user": {
"UserId": 4,
"FirstName": "John",
"MiddleName": null,
"LastName": "Doe",
"SecondLastName": null,
},
"medicalspecialty": {
"MedicalSpecialtyId": 3,
"Description": "Doctor"
}
}
]
But instead I'm getting this result:
[
{
"MedicId": 1,
"Code": "test1",
"user.UserId": 4,
"user.FirstName": "John",
"user.MiddleName": null,
"user.LastName": "Doe",
"user.SecondLastName": null,
"medicalspecialty.MedicalSpecialtyId": 3,
"medicalspecialty.Description": "Doctor"
}
]
This is how I'm pulling data:
static getAllMedics() {
MedicModel.belongsTo(MedicalSpecialtyModel, {
foreignKey: 'MedicalSpecialtyId'
});
MedicModel.belongsTo(UserModel, {
foreignKey: 'UserId'
});
UserModel.belongsTo(MedicModel);
MedicalSpecialtyModel.hasMany(MedicModel);
const attributes = ['MedicId', 'Code'];
return MedicModel.findAll({
attributes,
include: [{
model: UserModel,
attributes: ['UserId', 'FirstName', 'MiddleName', 'LastName', 'SecondLastName'],
where: {
Deleted: false
},
required: true,
nested: true
}, {
model: MedicalSpecialtyModel,
attributes: ['MedicalSpecialtyId', 'Description'],
required: true,
nested: true
}],
raw: true
});
}
Hope you can help me.
The raw property on a find call flattens the structure.
Basically do a find without raw: true.
You could get more info about it here
At the end it was my error.
When initializing Sequelize I had added the option row: true.
new Sequelize(..., {
...,
row: true
})
My apologies.

Resources