Rename column in sequelize findAll - node.js

I have the following findAll query:
let consumQuery = Manager.consumption.findAndCountAll({
where: query, attributes: ['ml', 'price', 'total', 'consumption_end', 'bar_id', 'sync', 'visit.device_id',
'visit.person.document','visit.person.person_id','visit.person.name','visit.person.surname',
'keg.product_id','keg.product.sku','keg.product.name'],
include: [
{
model: Manager.visit,
attributes: [],
include: [{
model: Manager.person,
attributes: [],
raw: true
}],
},
{
model: Manager.keg,
attributes: [],
include: [
{
model: Manager.product,
required: true,
attributes: []
}
]
}],
limit: PAGE_LIMIT_SIZE,
offset: offset,
raw: true,
order: [['consumption_start', 'ASC']]
}).then(({count, rows}) => {
I'm trying to rename the column keg.product.name to beer.
I've tried :
...'keg.product_id','keg.product.sku',['keg.product.name','beer']
But I got the error:
"column \"keg.product.name\" does not exist"
The sequelize output the following SQL:
sql: `SELECT "consumption"."ml", "consumption"."price", "consumption"."total", "consumption"."consumption_end", "consumption"."bar_id", "consumption"."sync", "visit"."device_id", "visit.person"."document", "visit.person"."person_id", "visit.person"."name", "visit.person"."surname", "keg"."product_id", "keg.product"."sku", "keg.product.name" AS "beer" FROM "public"."consumption" AS "consumption" LEFT OUTER JOIN "public"."visit" AS "visit" ON "consumption"."visit_id" = "visit"."visit_id" LEFT OUTER JOIN "public"."person" AS "visit.person" ON "visit"."person_id" = "visit.person"."person_id" LEFT OUTER JOIN "public"."keg" AS "keg" ON "consumption"."keg_id" = "keg"."keg_id" INNER JOIN "public"."product" AS "keg.product" ON "keg"."product_id" = "keg.product"."product_id" WHERE ("consumption"."bar_id" = '248' AND "consumption"."sync" = 'true' AND "consumption"."consumption_start" >= '2020-02-16 20:03:32.000 -03:00' AND "consumption"."consumption_end" <= '2020-09-17 20:03:32.000 -03:00') ORDER BY "consumption"."consumption_start" ASC LIMIT 500 OFFSET 0;},
The result is "keg.product.name" AS "beer", but I think should be something like that: "keg.product"."name" AS "beer"
Any ideia?

To rename an attribute you have to make it an array like [name_in_db, name_you_want].
Therefore your attributes value should be as it follows
attributes: ['ml', 'price', 'total', 'consumption_end', 'bar_id', 'sync', 'visit.device_id', visit.person.document', 'visit.person.person_id', 'visit.person.name', 'visit.person.surname', keg.product_id', 'keg.product.sku', **['keg.product.name', 'beer']**]
Source: https://sequelize.org/api/v6/class/src/model.js~model#static-method-findAll
"To rename an attribute, you can pass an array, with two elements - the first is the name of the attribute in the DB [...], and the second is the name you want the attribute to have in the returned instance"

Related

Sequelizejs error to run function on columns - check_ungrouped_columns_walker in

I want to run a function in the attribute and get different between startDate and endDate. But when I execute the code get this error:
column "Signals.id" must appear in the GROUP BY clause or
be used in an aggregate function
const lastData = await psql.Signals.findAll({
attributes: [
"id",
"strategy",
"type",
"symbol",
"name",
"timeframe",
"status",
"startDate",
"endDate",
[
Sequelize.literal('EXTRACT(DAY FROM MAX("startDate")-MIN("endDate"))'),
"DateDifference"
],
"positionsData"
],
where: {
isMain: true,
strategy: {
[Op.in]: ["21", "22"]
}
},
order: [["id", "DESC"]],
limit: 50,
raw: true
})
The expected SQL code by Sequelizejs is:
SELECT "id", "strategy", "type", "symbol", "name", "timeframe", "status", "startDate", "endDate", EXTRACT(DAY FROM MAX("startDate")-MIN("endDate")) AS "DateDifference", "positionsData" FROM "signals" AS "Signals" WHERE "Signals"."isMain" = true AND "Signals"."strategy" IN ('21', '22') ORDER BY "Signals"."id" DESC LIMIT 50;
Can anybody help me? What is wrong?!
Summary functions (MIN, MAX, SUM, etc) usually require a GROUP BY clause. For what set of data should the MIN and MAX date fields be applied? Will there be multiple dates per id?

Is it possible to convert an array of json objects to a sequelize query?

I'm receiving an array of JSON objects from the client and I need to dynamically convert it to a sequelize query
I tried using switch cases such as case 'and' will make object.other = [op.and] and so on. But it doesn't work.
I expect to receive something like this:
[
{
other: "",
column: "name",
value: "Kevin"
}
{
other: "and",
column: "id",
value: "10"
}
]
and it should convert to
Model.findAll({
where: {
[Op.and]: [{name : 'Kevin'},{id: 10}]
}
})

sequelize indirect associations

I have 3 tables named projects,workspace,views and the associations are
projects.hasMany(workspace);
workspace.belongsTo(projects);
workspace.hasMany(views);
views.belongsTo(workspace);
I need to join these 3 tables to get the output of following query
select * from projects pro join workspace wrk on pro.id= wrk.project_id
join views on wrk.id = views.workspace_id
I tried an association
views.belongsTo(projects, { through: workspace.associations.projects });
Following is the code:
View.findAll({
include: [
{model: db.workspaces, required: true},
{model: db.projects, required: true}
]
});
But it generates the query
SELECT *
FROM "views" AS "views"
INNER JOIN "workspaces" AS "workspace" ON "views"."workspace_id" = "workspace"."id"
INNER JOIN "projects" AS "project" ON "views"."project_id" = "project"."id"
The project_id does not exists in views table.It associates the views only through workspace.How can it be achieved.
Try following
Project.hasMany(Workspace,{foreignKey : 'project_id'});
Workspace.belongsTo(Project);
Workspace.hasMany(views,{foreignKey: 'workspace_id'});
View.belongsTo(Workspace);
Workspace.findAll({
include: [
{model: View, required: true},
{model: Project, required: true}
]
});

where clause on include column using sequilize

I'm using this query:
db.Spectrum.findAll({
attributes: ['title', [db.Sequelize.fn('SUM', db.Sequelize.col('quantity') ), 'count']],
include: [
{model: db.Varietal,
attributes : ['specID', 'id'],
include : [
{ model : db.Wine,
required: false,
attributes : ['varietal_id', 'id'],
where : {restaurant_id : restaurant_id,
owner_id : null} }
],
}
],
group : ['specID']
})
Which gives me the correct results, the problem is because it ands the where clause to the left join it runs really slow (about 2 seconds).
The raw query of the left join looks like this.
LEFT OUTER JOIN `wines` AS `Varietals.Wines` ON `Varietals`.`id` = `Varietals.Wines`.`varietal_id` AND `Varietals.Wines`.`restaurant_id` = 16 AND `Varietals.Wines`.`owner_id` IS NULL
I would like the query to have the left join and a where clause like this..
LEFT OUTER JOIN `wines` AS `Varietals.Wines` ON `Varietals`.`id` = `Varietals.Wines`.`varietal_id`
WHERE `Varietals.Wines`.`restaurant_id` = 16 AND `Varietals.Wines`.`owner_id` IS NULL
But everything I try puts 'Spectrum' before it and then doesn't find the row. How is this suppose to be done? Or am I going to have to just use a raw query?
include.where will always add the condition to the join.
However in Sequelize v3.13.0 support for special nested keys were added.
It's now possible to add a where object to the toplevel object containing dot seperated keys wrapped in $ to specify it being a nested field.
Applying it to your code:
db.Spectrum.findAll({
include: [
{
model: db.Varietal,
include : [
{
model : db.Wine
}
]
}
],
where: {
'$Varietals.Wines.restaurant_id$': restaurant_id,
'$Varietals.Wines.owner_id$': null
},
group : ['specID']
});
(I removed a few statements to focus on the important part)
Include array
include = [{
model: db.caregiverCategory,
as: 'categories',
attributes: ['name'],
required: true,
attributes: ['name'],
include: [{
model: db.category,
as: 'category',
required: true
}]
}]
Where Clause
where[Op.or] = [{
'$categories.name$': { [Op.like]: '%' + query.category_name + '%' }
}, {
'$categories.category.name$': { [Op.like]: '%' + query.category_name + '%' }
}]
You need to add all fields like name (which are required in or) in attributes: ['name'] otherwise it will give unknowm columns error.

Sequelize produces invalid query "model.id AS model.id"

Here is the sequelize call I'm making to count favorites along with my model:
Model.findAll({
group: [ 'model.id', 'favorites.id' ],
attributes: [
'*',
[ Sequelize.fn('count', Sequelize.col('favorites.id')), 'favorites_count' ]
],
include: [
{ attributes: [], model: Favorite },
]
});
Here's the query it produces:
SELECT
model.id,
model.*,
count(favorites.id) AS favorites_count,
favorites.id AS favorites.id # Invalid!
FROM models AS model ...
Here's the error
ERROR: syntax error at or near "."
LINE 1: SELECT model.*, favorites.id AS favorites.id, ...
^
Because favorites.id is not a valid AS alias. Why does Sequelize produce this
invalid alias and how do I prevent it?
You cannot prevent it - sequelize needs to alias the column. The query becomes invalid because you have set quoteIdentifiers to false. The query sequelize wants is "favorites"."id" AS "favorites.id"
Why is sequelize doing such a "stupid" thing you might say. Well lets take an example:
SELECT "model"."id", "favorites"."id" ...
This produces the following result set:
[{ id: 42 }]
Because the two columns have the same name, they override each other so only one of the columns is returned. So we need to alias the favorites column so we get
[{ id: 42, 'favorites.id': 87 }]

Resources