How to rename entity name in Sequelize result? - node.js

How can i change entity name in sequelize result ?
Result in postman
"createDate": "2019-05-30",
"companyHeader.companyName": "Testcomp"
I want to rename 'companyHeader.companyName' -> 'companyName'
repository.js
return await models.userHeader.findAndCountAll({
// join t_userheader and t_companyheader with associate
include: [
{
model: models.companyHeader,
attributes: ["companyName"],
// as : 'company'
},
],
attributes: ["id","userId", "userName", "usedCode", "createDate"],
offset: offset,
limit: pageAmount,
order : [['createdate','DESC']],
raw : true
});

You need to use sequelize.literal on the attributes of the first model as this:
return await models.userHeader.findAndCountAll({
include: [{
model: models.companyHeader,
attributes: ["companyName"],
// as : 'company'
}],
attributes: [
"id",
"userId",
"userName",
"usedCode",
"createDate",
[sequelize.literal('"companyHeader"."companyName"'), 'companyName']
],
offset: offset,
limit: pageAmount,
order : [['createdate','DESC']],
raw : true
});

module.exports = (sequelize, DataTypes) => {
const userHeader = sequelize.define("userHeader",{
id: {
type: DataTypes.UUID,
allowNull: false,
unique: true,
primaryKey: true,
autoIncrement: true,
defaultValue : sequelize.literal('uuid_generate_v4()'),
},
userId: {
type: DataTypes.STRING(),
field : 'userid'
},
password: {
type: DataTypes.STRING(),
allowNull: false,
field : 'password'
},
userName: {
type: DataTypes.STRING(),
allowNull: true,
field : 'username'
},
usedCode: {
type: DataTypes.INTEGER,
allowNull: false,
field : 'usedcode'
},
companyId: {
type: DataTypes.UUID,
allowNull: false,
field : 'companyid'
},
createDate: {
type: DataTypes.DATE(3),
allowNull: false,
defaultValue: sequelize.literal("CURRENT_TIMESTAMP(3)"),
field : 'createdate'
}
userHeader.associate = function(models) {
// associations
userHeader.belongsTo(models.companyHeader,{
foreignKey: 'companyId',
targetKey : 'id',
// as : 'company'
})
};
return userHeader;
};

Related

Sequelize self-referential Many-to-Many relationships are not working

I only found following in Sequelize documentation, but it's not possible to understand how to fetch associations properly.
Person.belongsToMany(Person, { as: 'Children', through: 'PersonChildren' })
// This will create the table PersonChildren which stores the ids of the objects.
This is the implementation.
const sequelizePsqlConfig = new Sequelize(
"postgres://Kavinda Vindika#localhost:5432/hrm_users"
);
export const User = sequelizePsqlConfig.define(
"users",
{
userId: {
field: "user_id",
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
userName: {
field: "user_name",
type: DataTypes.STRING,
},
email: { type: DataTypes.STRING, key: "email" },
department: { type: DataTypes.STRING, key: "department" },
designation: { type: DataTypes.STRING, key: "designation" },
},
{
timestamps: false,
}
);
export const User_Associations = sequelizePsqlConfig.define(
"user_associations",
{
id: {
field: "id",
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
managerId: {
field: "manager_id",
type: DataTypes.INTEGER,
},
subordinateId: {
field: "subordinate_id",
type: DataTypes.INTEGER,
},
},
{
modelName: "user_associations",
timestamps: false,
tableName: "user_associations",
}
);
User.belongsToMany(User, {
as: "manager",
through: "user_associations",
foreignKey: "manager_id",
otherKey: "subordinate_id",
});
User.belongsToMany(User, {
as: "subordinate",
through: "user_associations",
foreignKey: "subordinate_id",
otherKey: "manager_id",
});
Then I tried to fetch the data with manager and subordinate details.
public async getAllUsers() {
return User.findAll({
include: ["manager", "subordinate"],
});
}
But it failed with following logs. Please assist me on this issue.
[1] Executing (default): SELECT "users"."user_id" AS "userId", "users"."user_name" AS "userName", "users"."email", "users"."department", "users"."designation", "manager"."user_id" AS "manager.userId", "manager"."user_name" AS "manager.userName", "manager"."email" AS "manager.email", "manager"."department" AS "manager.department", "manager"."designation" AS "manager.designation", "manager->user_associations"."id" AS "manager.user_associations.id", "manager->user_associations"."manager_id" AS "manager.user_associations.managerId", "manager->user_associations"."subordinate_id" AS "manager.user_associations.subordinateId", "manager->user_associations"."manager_id" AS "manager.user_associations.manager_id", "manager->user_associations"."subordinate_id" AS "manager.user_associations.subordinate_id", "subordinate"."user_id" AS "subordinate.userId", "subordinate"."user_name" AS "subordinate.userName", "subordinate"."email" AS "subordinate.email", "subordinate"."department" AS "subordinate.department", "subordinate"."designation" AS "subordinate.designation", "subordinate->user_associations"."id" AS "subordinate.user_associations.id", "subordinate->user_associations"."manager_id" AS "subordinate.user_associations.managerId", "subordinate->user_associations"."subordinate_id" AS "subordinate.user_associations.subordinateId", "subordinate->user_associations"."manager_id" AS "subordinate.user_associations.manager_id", "subordinate->user_associations"."subordinate_id" AS "subordinate.user_associations.subordinate_id" FROM "users" AS "users" LEFT OUTER JOIN ( "user_associations" AS "manager->user_associations" INNER JOIN "users" AS "manager" ON "manager"."user_id" = "manager->user_associations"."subordinate_id") ON "users"."user_id" = "manager->user_associations"."manager_id" LEFT OUTER JOIN ( "user_associations" AS "subordinate->user_associations" INNER JOIN "users" AS "subordinate" ON "subordinate"."user_id" = "subordinate->user_associations"."manager_id") ON "users"."user_id" = "subordinate->user_associations"."subordinate_id";
[1] TypeError: Class constructor model cannot be invoked without 'new'

NodeJS - Sequelize how to declare association for eager loading only once to be used for queries later

The problem:
Whenever I fetch a user, I always have to declare/include the association on the query to get its role:
const user = await DB.PORTALDB.models.AccessUser.findOne({
where: { email },
include: [ // EVERY QUERY, I HAVE TO INCLUDE THIS
{
model: DB.PORTALDB.models.AccessUserRoleLup,
as: 'role'
}
]
});
Now there are instance where I forget to include this association so I get a undefined role.
My question is, is there a way where I only set this association once so that I don't have to include this later on my queries?
This the model for my AccessUser table
const AccessUser = <AccessUserStatic>sequelize.define<AccessUserInstance>(
'AccessUser',
{
user_id: {
autoIncrement: true,
type: DataTypes.INTEGER.UNSIGNED,
allowNull: false,
primaryKey: true
},
email: {
type: DataTypes.STRING(255),
allowNull: false
},
firstname: {
type: DataTypes.STRING(255),
allowNull: false
},
lastname: {
type: DataTypes.STRING(255),
allowNull: false
},
password: {
type: DataTypes.STRING(255),
allowNull: false
},
disable: {
type: DataTypes.TINYINT,
allowNull: false,
defaultValue: 0
},
role_id: {
type: DataTypes.SMALLINT,
allowNull: false,
defaultValue: 0
},
created_modified: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP')
}
}, {
tableName: 'access_user',
timestamps: false,
indexes: [
{
name: "PRIMARY",
unique: true,
using: "BTREE",
fields: [
{ name: "user_id" },
]
},
]
});
AccessUserRoleLup table
const AccessUserRoleLup = <AccessUserRoleLupStatic>sequelize.define<AccessUserRoleLupInstance>(
'AccessUserRoleLup',
{
role_id: {
autoIncrement: true,
type: DataTypes.INTEGER.UNSIGNED,
allowNull: false,
primaryKey: true
},
role_name: {
type: DataTypes.STRING(50),
allowNull: false
},
role_code: {
type: DataTypes.CHAR(50),
allowNull: false,
defaultValue: ""
}
}, {
tableName: 'access_user_role_lup',
timestamps: false,
indexes: [
{
name: "PRIMARY",
unique: true,
using: "BTREE",
fields: [
{ name: "role_id" },
]
},
]
});
Association:
db.models.AccessUser.hasOne(db.models.AccessUserRoleLup, {
foreignKey: 'role_id',
as: 'role'
});
Use defaultScope for AccessUser. defaultScope is defined in a model definition and it is always applied (unless you removed inline).
const AccessUser = <AccessUserStatic>sequelize.define<AccessUserInstance>(
'AccessUser',
{
user_id: {
autoIncrement: true,
type: DataTypes.INTEGER.UNSIGNED,
allowNull: false,
primaryKey: true
},
...
}, {
tableName: 'access_user',
timestamps: false,
defaultScope: { // Add this
include: [{
model: AccessUserRoleLup,
as: 'role'
}]
},
...
});
With this model definition, all queries will include AccessUserRoleLup.
If you would like to remove for a certain query, use .unscoped().
// These will automatically add eager loading for role
DB.PORTALDB.models.AccessUser.findAll()
DB.PORTALDB.models.AccessUser.findOne()
// These won't fetch role
DB.PORTALDB.models.AccessUser.unscoped().findAll()
DB.PORTALDB.models.AccessUser.unscoped().findOne()
More detail about scope: https://sequelize.org/master/manual/scopes.html
My initial workaround was to create a utility function for querying the user like so:
export const getAccessUser = (where: WhereOptions, include?: IncludeOptions) => {
return new Promise(async (resolve, reject) => {
try {
const user = await DB.PORTALDB.models.AccessUser.findOne({
where: where,
include: [
{
model: DB.PORTALDB.models.AccessUserRoleLup,
as: 'role'
},
...[include]
]
});
resolve(user);
} catch (err) {
reject(err);
}
});
}
I wonder if my question above can be done in much simpler way.

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

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

filter Sequelize belongsToMany

I have the following problem:
I defined my tables (product and collection) like this:
module.exports = (sequelize, type) => {
return sequelize.define('product', {
id: {
type: type.UUID,
primaryKey: true,
defaultValue: type.UUIDV4,
},
title: {
type: type.STRING,
allowNull: false,
},
description: {
type: type.TEXT,
allowNull: false,
},
width: {
type: type.FLOAT,
allowNull: false,
},
height: {
type: type.FLOAT,
allowNull: false,
},
weight: {
type: type.FLOAT,
allowNull: false,
},
length: {
type: type.FLOAT,
allowNull: false,
},
vendor: {
type: type.STRING,
allowNull: false,
},
status: {
type: type.ENUM,
values: ['inactive', 'active'],
defaultValue: 'active',
allowNull: false,
},
})
}
module.exports = (sequelize, type) => {
return sequelize.define('collection', {
id: {
type: type.UUID,
primaryKey: true,
defaultValue: type.UUIDV4,
},
name: {
type: type.STRING,
allowNull: false,
},
image: {
type: type.STRING,
allowNull: true,
},
createdAt: {
type: type.DATE,
allowNull: false,
},
updatedAt: {
type: type.DATE,
allowNull: false,
},
status: {
type: type.ENUM,
values: ['inactive', 'active'],
defaultValue: 'active',
allowNull: false,
},
})
}
Then, I need associated the tables (product and collection) with belongsToMany association and i did it like this:
const ProductModel = require('../api/product/model')
const CategoryModel = require('../api/category/model')
const Product = ProductModel(sequelize, Sequelize)
const Collection = CollectionModel(sequelize, Sequelize)
Product.belongsToMany(Collection, {
through: ProductCollection,
foreignKey: 'productId',
otherKey: 'collectionId',
unique: false,
})
Collection.belongsToMany(Product, {
through: ProductCollection,
foreignKey: 'collectionId',
otherKey: 'productId',
unique: false,
})
Now, i want to get all the products of a collection given by the id sent from the body of the request, i have little time working with sequelize and i donĀ“t know how to do this kind of query.
Can you help me with that?
you can use something like this
let products = Collection.findAll({
where: {
id: collection.id,
},
attributes: ['id', 'name'],
include: [{
model: Product,
through: {
model: ProductCollection,
},
as: 'products',
attributes: ['id', 'title', 'description']
}],
});
return products
hope it helps

Resources