join same table in sequelize and print in excel - node.js

I want to print parent name in excel
this is my code
function getReportT0Print(req, res) {
return new Promise((resolve, reject) => {
Product.findAll({
where: {
$and: [
{
public: true,
visible: true,
ancestry: {
$not: null,
},
},
],
},
include: [
{
model: ormDb.Document,
required: false,
},
],
attributes: ["name", "slug", "folder_path"],
})
.then(function (data) {
// console.log("data" + data.length);
var rows = [];
rows.push(["Product Name", "Slug", "File Path", "Product Parent Name"]);
data.map(function (product) {
rows.push([
product.name,
product.slug,
product.folder_path,
(here i need to print parent name)
]);
});
var workbook = new Excel.Workbook();
var sheet = workbook.addWorksheet("products_with_tags");
sheet.addRows(rows);
resolve(workbook);
return res.send("successfull");
})
.catch(function (err) {
reject(err);
});
});
}
i can print name, slug,folder_path but i don't know how to print parent name in excel file
as parent name is not present but i have given parent_id in place of parent name and want to print parent name
my SQl table look like this
("id" "name" "version" "published" "reviewed" "visible" "public", "parent_id")

You need to register an association between two Product models like this:
Product.belongsTo(Product, { foreignKey: 'parent_id', as: 'parent' });
You can place it in some module outside model's module file where you create Sequelize instance, for example.
To use this association you need to use the same include option as you did with Document:
Product.findAll({
where: {
$and: [
{
public: true,
visible: true,
ancestry: {
$not: null,
},
},
],
},
include: [
{
model: Product,
as: 'parent',
required: false, // or true if parent_id is required field
// or you wish to get all products with parents
attributes: ["name", "slug", "folder_path"],
},
{
model: ormDb.Document,
required: false,
},
],
attributes: ["name", "slug", "folder_path"],
})

Related

Counting number of associated rows in sequelize

I am trying to find the count of students inside the classStudents association. Here teacher_details table is connected to class_details tables using 'section'
association and class_details tables is connected to student_details table using 'classStudents' association. I have tried the below method but got error ==>
Unknown column 'section->classStudents.studentId' in 'field list'
please let me know the correct procedure to count the associated students count
const getAssignedDetails = async (req, res) => {
try {
const assignedDetails = await Entity.teacherAssignedDetail.findAll({
where: { status: 1, teacherId: req.teacherId },
attributes: [
'role',
[
Sequelize.fn(
'COUNT',
Sequelize.col('section.classStudents.studentId')
),
'studentCount',
],
],
include: [
{
association: 'section',
attributes: ['sectionId', 'className', 'classEmoji'],
include: [
{
association: 'classStudents',
where: { status: 1 },
required: false,
},
],
where: { status: 1 },
},
{
association: 'subjectDetails',
attributes: [['id', 'masterSubjectId'], 'subjectName'],
},
],
});
res.json({
responseCode: 0,
responseMessage: 'Success',
responseData: assignedDetails,
});
} catch (err) {
res.status(500).send(errorHandling(err.message));
}
};

Sequelize - Select on associated table

My problem:
I am creating an route which will return some informations about a group, it has an id, an user assigned and also has some documents. I just want to show how much documents exists, in SQL would be SELECT COUNT, but how can i do this in this in sequelize?
My code:
async list(req, res){
const docGroups = await DocGroup.findAll({
raw: true,
include: [{
model: User,
as: 'userAssigned'
},
{
model: Document,
as: 'Document'
}
]
}).then(groups => {
const result = groups.map(group => {
return Object.assign(
{},
{
id: group.id,
name: group.name,
userAssinged: group['userAssigned.firstName'],
docAmount: // I want to put documents' count here
}
)
})
console.log(groups)
})
}
What is printed in console.log(groups):
[
{
id: 1,
name: 'pleaseworks',
createdAt: 2020-06-10T02:38:11.531Z,
updatedAt: 2020-06-10T02:38:11.531Z,
'userAssigned.id': 1,
'userAssigned.firstName': 'Please',
'userAssigned.lastName': 'Works',
'userAssigned.email': 'pleaseworks#gmail.com',
'userAssigned.password': '$2a$08$3BA4I4dsaQ3lsHy342344b5P41v5eHWjwqv6dve28nSdqbGvhsdS',
'userAssigned.createdAt': 2020-06-10T02:37:29.062Z,
'userAssigned.updatedAt': 2020-06-10T02:37:29.062Z,
'userAssigned.groupId': null,
'Document.id': 2,
'Document.description': 'deowkdopewkdwe',
'Document.content': 'odepodkewokodwe',
'Document.groupId': 1,
'Document.createdAt': 2020-06-10T02:43:46.005Z,
'Document.updatedAt': 2020-06-10T02:43:46.005Z
}
]
If DocGroup has many Document try something like this:
{
model: Document,
attributes: [[sequelize.fn('COUNT', sequelize.col('id')), 'docAmount']]
as: 'Document'
}

how to merge response attributes of other table in node js

I have 3 Tables User, Cars and UserCars
User{id, name, phone, email}
Cars{id, name, manufacturer}
UserCars{id, car_id, user_id, role}
User have many cars(through UserCars)
Cars have many users(through UserCars)
I am using express js
router.get('/', async (req, res) => {
try {
let car = await Car.findOne({
where: {
id: req.car_id
}});
let users = await car.getUsers({joinTableAttributes: ['role']})
res.send(users)
} catch (e) {
console.log(e)
res.status(400).send(e)
}
})
and this my response
[
{
"id": 1,
"name": "test",
"email": null,
"phone": null,
"createdAt": "2019-07-09T09:38:11.859Z",
"updatedAt": "2019-07-12T04:34:20.922Z",
"User_car": {
"role": "driver"
}
}
]
but any idea how to include role in the user object, rather then specifying it separately in User_car table,
Is there a way where i can get the below output
[
{
"id": 1,
"name": "test",
"email": null,
"phone": null,
"role": 'driver'
"createdAt": "2019-07-09T09:38:11.859Z",
"updatedAt": "2019-07-12T04:34:20.922Z"
}
]
You can use sequelize.literal to get that field when getting your attributes.
attributtes: [
// define your other fields
[sequelize.literal('`users->User_car`.`role`'), 'role'],
]
Now, I not sure if that is going to work with car.getUsers. I usually do a single query with include and also define the "join" table so I can know how is name it on sequelize. Let me show you an example.
module.exports = (sequelize, DataTypes) => {
const UserCar = sequelize.define('UserCar', {
// id you don't need and id field because this is a N:M relation
role: {
type: DataTypes.STRING
},
carId: {
field: 'car_id',
type: DataTypes.INTEGER
},
userId: {
field: 'user_id',
type: DataTypes.INTEGER
},
}, {
tableName: 'User_car',
underscored: true,
createdAt: 'created_at',
updatedAt: 'updated_at',
});
UserCar.associate = (models) => {
models.user.belongsToMany(models.car, { as: 'cars', through: User_car, foreignKey: 'user_id' });
models.car.belongsToMany(models.user, { as: 'users', through: User_car, foreignKey: 'car_id' });
};
return UserCar;
};
router.get('/', async (req, res) => {
try {
const users = await User.findAll({
include: [{
model: Car,
as: 'cars',
where: { id: req.car_id }
}],
attributtes: [
'id',
'name',
'email',
'phone',
[sequelize.literal('`cars->User_car`.`role`'), 'role'],
]
})
res.send(users)
} catch (e) {
console.log(e)
res.status(400).send(e)
}
});

SequelizeJS, Is this a best way to create this JSON Result using this models

I want this result, but, is so complicated do to this in this way. There is a better way to create this result using Sequelize. Using the querys tools of sequelize to aggregate results from diferent tables, on JPA the only thing i do is annotate with join table and pass the columns ad invese columns values.
[
{
"id": 1,
"codemp": "999",
"nome": "A3 Infortech",
"limiteInstancias": "10",
"instancias": []
},
{
"id": 2,
"codemp": "92",
"nome": "Endovideo",
"limiteInstancias": "20",
"instancias": [
{
"id": 198211,
"ipLocal": "40.0.10.11",
"ipExterno": "187.33.230.106",
"hostname": "FATURAMENTO-PC",
"dataCriacao": "2019-07-01T21:40:29.000Z"
}
]
},
{
"id": 6,
"codemp": "103",
"nome": "SOS Otorrino",
"limiteInstancias": "999",
"instancias": [
{
"id": 199127,
"ipLocal": "192.168.11.101",
"ipExterno": "000.000.000.000",
"hostname": "Guiche3-PC",
"dataCriacao": "2019-07-01T21:40:32.000Z"
},
{
"id": 199164,
"ipLocal": "192.168.25.209",
"ipExterno": "000.000.000.000",
"hostname": "Consultorio06",
"dataCriacao": "2019-07-01T21:40:29.000Z"
}
]
},
{
"id": 15,
"codemp": "162",
"nome": "Clinica Vida e Saude",
"limiteInstancias": "10",
"instancias": [
{
"id": 199774,
"ipLocal": "192.168.56.1",
"ipExterno": "000.000.000.000",
"hostname": "ALEXANDRELEAL",
"dataCriacao": "2019-07-01T21:40:28.000Z"
}
]
}
]
I have this codes:
Empresa Model
module.exports = (sequelize, DataTypes) => {
const empresa = sequelize.define("empresa", {
id: {
type: DataTypes.BIGINT(20),
primaryKey: true,
field: "id"
},
codemp: {
type: DataTypes.INTEGER,
field: "codemp"
},
nome: {
type: DataTypes.STRING,
field: "nome"
},
limiteInstancias: {
type: DataTypes.INTEGER,
field: "limite_instancias"
}
}, {
timestamps: false,
freezeTableName: true,
tableName: "empresa"
});
empresa.associate = (db) => {
console.log(db);
empresa.hasMany(db.instanciaEmpresa, {foreignKey: "id_empresa"});
};
return empresa;
};
Instancia Model
module.exports = (sequelize, DataTypes) => {
const instancia = sequelize.define("instancia", {
id: {
type: DataTypes.BIGINT(20),
primaryKey: true,
field: "id"
},
ipLocal: {
type: DataTypes.STRING,
field: "ip_local"
},
ipExterno: {
type: DataTypes.STRING,
field: "ip_externo"
},
hostname: {
type: DataTypes.STRING,
field: "hostname"
},
dataCriacao: {
type: DataTypes.DATE,
field: "data_criacao"
},
}, {
timestamps: false,
freezeTableName: true,
tableName: "instancia"
});
instancia.associate = (db) => {
console.log(db);
instancia.belongsTo(db.empresa, {foreignKey: "id_instancia"});
};
return instancia;
};
InstanciaEmpresa Model
module.exports = (sequelize, DataTypes) => {
const instanciaEmpresa = sequelize.define("instancia_empresa", {
idEmpresa: {
type: DataTypes.BIGINT(20),
primaryKey: true,
field: "id_empresa"
},
idInstancia: {
type: DataTypes.BIGINT(20),
primaryKey: true,
field: "id_instancia"
},
}, {
timestamps: false,
freezeTableName: true,
tableName: "instancia_empresa"
});
return instanciaEmpresa;
};
My Database diagram.
A picture of my database diagram
The code of my response
const db = require("../config/db.config");
const empresa = db.empresa;
const instancia = db.instancia;
const instanciaEmpresa = db.instanciaEmpresa;
const empressaResult = [];
module.exports = {
async getAll(req, res) {
return res.send(await getAllEmpresa());
}
};
async function getAllEmpresa() {
//Recover all companies from the table
let empresaList = await empresa.findAll({raw: true});
//I browse the array of companies to retrieve the instances associated with the company
for(let i = 0; i < empresaList.length; i++){
//Create the atribute Instancias[]
empresaList[i].instancias = [];
//I retrieve the list of associated instances in the InstanciaEmpresa table
let instanciasEmpresa = await instanciaEmpresa.findAll({where: {"id_empresa": empresaList[i].id}, raw: true});
//Verify if existes any item of InstanciaEmpresa
if(instanciasEmpresa.length > 0){
//If there is a run through list of instances
for(let j = 0; j < instanciasEmpresa.length; j++){
//I retrieve the Instancia in the database and add it to the company Instancias list
let inst = await instancia.findByPk(instanciasEmpresa[j].idInstancia, {raw: true});
empresaList[i].instancias.push(inst);
}
}
//I add the company with the instances in a result list;
empressaResult.push(empresaList[i]);
}
return empressaResult;
}
You can use include option to operate join on your tables.
Then your code would look like,
const empresaList = await empresa.findAll({
raw: true,
include: [
{
model: instancias,
required: false, // left join, `true` means inner join.
}
]
});
As you can see, you can pass array of { model, required } into include option.
You can set required to true if you want to operate inner join else it would operate left join.
--- ADDED ---
SequelizeEagerLoadingError: instancia is not associated to empresa means you're not calling associate function on db initialization.
You can write helper function like below in your db.js.
addAssociations(name) {
if (this[name].associate) {
this[name].associate(this);
}
}
}
and use it like
/*
* this.models = [
* {
* name: 'instancias',
* model: instancias,
* },
* ... and many more
* ]
*/
this.models.forEach((value) => {
this.addAssociations(value.name);
});

How to get data from different schema in Nodejs

I have two schemas called employees (parent) and assessments(child)
Every assessment will have a pass percentage of employee id
so I have results like this
employees : [
{
"_id": 12345,
"name": "David",
"evaluated": false
},
{
"_id": 12346,
"name": "Miller",
"evaluated": false
}
]
Second Schema
assessments: [
{
"assessment_type": "basic",
"employee_id": 12345,
"qualified": true
},
{
"assessment_type": "advanced",
"employee_id": 12345,
"qualified": false
},
{
"assessment_type": "basic",
"employee_id": 12346,
"qualified": true
},
{
"assessment_type": "advanced",
"employee_id": 12346,
"qualified": true
}
]
So I want to get the employees with evaluated based on assessments qualified is true
can you please tell me what is the best approach for this?
Here is an example where we sort the employees by the assements they succeeded.
const employees = [{
_id: 12345,
name: 'David',
evaluated: false,
}, {
_id: 12346,
name: 'Miller',
evaluated: false,
}];
const assessments = [{
assessment_type: 'basic',
employee_id: 12345,
qualified: true,
}, {
assessment_type: 'advanced',
employee_id: 12345,
qualified: false,
}, {
assessment_type: 'basic',
employee_id: 12346,
qualified: true,
}, {
assessment_type: 'advanced',
employee_id: 12346,
qualified: true,
}];
// Loop at the employees
const sortByAssessment = employees.reduce((tmp, x) => {
// Get all the assessment about the employee
const employeeAssessment = assessments.filter(y => y.employee_id === x._id);
// Deal with each assessment
employeeAssessment.forEach((y) => {
// Only do something about successfull assessments
if (y.qualified) {
// In case this is the first time we are dealing with the assessment_type
// create an array where we are going to insert employees informations
tmp[y.assessment_type] = tmp[y.assessment_type] || [];
// Push the name of the employee inside of the assessment type array
tmp[y.assessment_type].push(x.name);
}
});
return tmp;
}, {});
console.log(sortByAssessment);
you can do 2 things join with $look up or populate with employee id
assessments.aggregate([
{
'$lookup': {
'from': 'employees',
'localField': 'employee_id',
'foreignField': '_id',
'as': 'datas'
}
},
{ "$unwind": "$datas" },
].exec(function(err,result){
console.log(result)
});
2nd way
//assessments your model name
assessments.populate('employee_id').exec(function(err,result){
console.log(result);
});

Resources