left join on same table in sequelize - node.js

I want to write following query in sequelize but Not able to understand how to do.
SELECT * FROM RegisterUser AS RegisterUser
LEFT OUTER JOIN Notification as Noti ON PM_UserID = Noti.ReceiveID
LEFT OUTER JOIN RegisterUser AS RegisterUser1 ON
Noti.SenderId = RegisterUser1.PM_UserID
WHERE RegisterUser.PM_UserID = ReceiveID
I have written below query as a single left join and it works fine.
RegisterUser.findAll({
include: [
{
model: Notification,
as: 'NotificationrecipientId',
required: false,
},
],
raw: true });
And my assciotion is as follow:
db.RegisterUser.hasMany(db.Notifications, { as: 'NotificationrecipientId', foreignKey: 'ReceiveID' });
Sender ID as well in Register User table.

For that you have define one more association :
db.Notification.belongsTo(db.RegisterUser, { as: 'Sender', foreignKey: 'SenderId' });
and then use it like :
RegisterUser.findAll({
include: [{
model: Notification,
as: 'NotificationrecipientId',
required: false,
include: [{
model: RegisterUser,
as: 'Sender', // <---- HERE
required: false,
}, ]
}, ],
raw: true
});

Related

How do I eager load multiple foreign keys including an or query from the same table, in Sequelize?

I'm searching for the captain.entry_date but I'm not able to create the query in a sequelize model.
My problem is that for any ship exists a captain but the ship_captain.captain_id sometimes is null.
For this cases the captain can be found about the route_id.
4 Tables :
ship, attributes:[id,name],
captain, attributes: [id, name, route_id, route_date]
ship_captain, attributes: [id, ship_id, route_id, captain_id]
route, attributes: [id, name]
select ship.name, c.name, c.entry_date
from ship left join ship_captain sc on ship.id = sc.ship_id
left join captain c on c.id = sc.captain_id or c.route_id = sc.route_id
What I've try so far is this but I can't give an OR operator into the last join
Ship.hasMany(ShipCaptain, {foreignKey: "ship_id"});
ShipCaptain.belongsTo(Ship, {foreignKey: "ship_id"});
Captain.hasMany(ShipCaptain, {as: "ship_captain_by_id", foreignKey: "captain_id"});
ShipCaptain.belongsTo(Captain, {as: "ship_captain_by_route", foreignKey: "captain_id"});
Captain.hasMany(ShipCaptain, {as: "ship_captain_by_route", foreignKey: "route_id"});
ShipCaptain.belongsTo(Captain, {as: "ship_captain_by_route", foreignKey: "route_id"});
const options = {
attributes: ["name"],
include: [
{
model: Captain,
as: 'ship_captain_per_id',
required: false,
attributes: ["name","route_date"],
},
{
model: Captain,
as: 'ship_captain_per_route',
required: false,
attributes: ["name","route_date"],
}
],
}
const elements = await Ship.findAll(options);
This is only an example code, may be that you want to rearrange the db attributes
but I tried to give my best to clarify the problem. I can't change the customers database.
If you really want to use only one association to get a captain by captain_id or route_id and not to use two associations and map them yourself then you need to define only one association hasOne (instead of hasMany) and always use the on option to join ShipCaptain with Captain by OR:
Ship.hasMany(ShipCaptain, {foreignKey: "ship_id"});
ShipCaptain.belongsTo(Ship, {foreignKey: "ship_id"});
ShipCaptain.belongsTo(Captain, {as: "captain_by_captain", foreignKey: "captain_id"});
...
const options = {
attributes: ["name"],
include: [
{
model: ShipCaptain,
required: false,
include: [{
model: Captain,
required: false,
as: 'captain_by_captain',
attributes: ["name","route_date"],
on: {
[Op.or]: [{
id: Sequelize.col('ship_captain.captain_id'
}, {
id: Sequelize.col('ship_captain.route_id'
}]
}
}
]
},
],
}
const elements = await Ship.findAll(options);

How to solve "Not unique table/alias"? (node, sequelize)

I am implementing a comment service using 'express' and 'sequelize' modules. This comment service supports 'reply'. The model has 'user' and 'comment'.
Comment.hasMany(Comment, {foreignKey: {name: 'parent_comment', allowNull: true}, as: 'reply'});
Comment.belongsTo(Comment, {foreignKey: {name: 'parent_comment', allowNull: true}, as: 'parent'});
User.hasMany(Comment, {foreignKey: {allowNull: false}, onDelete: 'CASCADE'});
Comment.belongsTo(User, {foreignKey: {allowNull: false}, onDelete: 'CASCADE'});
I want to join the user by bringing in the "reply" part of the comment. like below...
[
{
somedata...,
writer: { // User model
userdata....
},
reply: [
{
somedata....
writer: { // User model
userdata....
}
},
....
]
},
....
]
However, as a result, an error occurs while outputting a message of 'Not unique table/alias'. Erase the marked 'this line' part and bring it normally, but it's not the desired result. code like this,
const c = await Comment.findAll({
include: [
{
model: User
},
{
model: Comment,
include: [{ model: User}] //// this line!
},
]
});
How can I get the results I want? Thank you.
Because Comment has 2 relationships with Comment (of course with aliases) you always need to indicate a desired alias in queries when you need to include Comment in Comment:
const c = await Comment.findAll({
include: [
{
model: User
},
{
model: Comment,
as: 'reply', // or as: 'parent' depending on your goal
include: [{ model: User}]
},
]
});

Sequelize Query take all values in where condition

I have an array=[1,2,3]
Only 1 & 2 are in the database under the column ID.
When I perform a query using WHERE IN it gives me result of 1 & 2.
What I want to do is if all data matches then show me the result otherwise null
I am using Sequelize. How can this be done?
Query:
Models.Question.findOne({
where: {
id:1
},
include: [{
model: Models.QuestionOptions,
as: 'options',
required: true,
where: {
id:[1,2,3]
}
}]
});
expect result Null because only 1 & 2 are in DB
require:true means INNER JOIN. In other words it will only return lines with existing associations(If the condition is also true of course). You should remove it if you want to get all lines(Left Join) even if there is no corresponding association
You can achieve this using group and having clause.
Models.Question.findOne({
attributes: ["id"],
where: {
id:1
},
group: ['id'],
having: sequelize.where(sequelize.fn('count', sequelize.col('options.id')), {
[sequelize.Op.gte]: 3,
}),
include: [{
model: Models.QuestionOptions,
as: 'options',
attributes: [],
required: true,
where: {
id:[1,2,3]
}
}]
});

Node.js sequelize model - can I define order of records on the model?

I am newish to node, and can't figure out how to only return 1 record of a hasMany relationship, based on an attribute.
There's a user, level, and levels_user table.
On user, I want to include 1 levels_user where level_id is highest.
Can I put a condition on this model file, something like:
order_by: ['level_id', 'DESC']
LevelsUsers Model
'use strict';
module.exports = (sequelize, DataTypes) => {
let LevelsUsers = sequelize.define('LevelsUsers', {
user_id: DataTypes.INTEGER,
level_id: DataTypes.INTEGER,
created_at: DataTypes.DATE,
updated_at: DataTypes.DATE,
},{
timestamps: false,
freezeTableName: true,
schema: "public",
tableName: "levels_users"
});
return LevelsUsers;
};
Users model association:
Users.hasMany(models.LevelsUsers, {
as: 'levels_users',
targetKey: 'id',
foreignKey: 'user_id',
});
This is my call:
users.getProfileByUserId = (req, res) => {
models.Users.findOne({
where: {id: req.params.userid},
include: [
{
model: models.LevelsUsers,
as: 'levels_users',
limit: 1,
}
]
order: []
}).then(user ....
I tried adding:
`order: [
[ models.LevelsUsers , 'level_id', 'DESC']
]`
Did not work and I think it's evaluated after limit: 1 anyways.
Can I put order_by on the model, to return highest to lowest by level_id each time? If not, what's a better way to accomplish returning only the highest levels_users record where level_id is highest?
The hasMany property is more suited when you want to include all the levels in the user object. In your case, I would advise to just pull the user without it's levels, and then do a second request to pull the higher level linked to that user by querying directly the LevelsUsers model :
models.LevelsUsers.findAll({
where: {
user_id: user.id,
},
order: ['level_id', 'DESC'],
limit: 1,
});
Well i reading over the documentation of sequelize for working with ordering and limit inside the includes tag.
Update query
users.getProfileByUserId = (req, res) => {
models.Users.findOne({
where: {id: req.params.userid},
include: [
{
model: models.LevelsUsers,
as: 'levels_users',
order: [
[ { model: models.LevelsUsers }, 'level_id', 'DESC']
],
limit: 1,
}
]
}).then(user ....
For references go over the following links - https://github.com/sequelize/sequelize/issues/4553#issuecomment-341261957

unknown column in field list sequelize

I'm trying to perform the following query using Sequelize:
db.Post.findAll({
include: [
{
model: db.User,
as: 'Boosters',
where: {id: {[Op.in]: a_set_of_ids }}
},
{
model: db.Assessment,
as: 'PostAssessments',
where: {UserId: {[Op.in]: another_set_of_ids}}
}
],
attributes: [[db.sequelize.fn('AVG', db.sequelize.col('Assessments.rating')), 'average']],
where: {
average: 1
},
group: ['id'],
limit: 20
})
But I run to this error: "ER_BAD_FIELD_ERROR". Unknown column 'Assessments.rating' in 'field list', although I do have table "Assessments" in the database and "rating" is a column in that table.
My Post model looks like this:
const Post = sequelize.define('Post', {
title: DataTypes.TEXT('long'),
description: DataTypes.TEXT('long'),
body: DataTypes.TEXT('long')
}, {
timestamps: false
});
Post.associate = function (models) {
models.Post.belongsToMany(models.User, {as: 'Boosters', through: 'UserPostBoosts' });
models.Post.hasMany(models.Assessment, {as: 'PostAssessments'});
};
What am I doing wrong?
It seems like this problem surfaces when we have a limit in a find query where associated models are included (the above error doesn't show up when we drop the limit from the query). To solve that, we can pass an option subQuery: false to the find. (https://github.com/sequelize/sequelize/issues/4146)
This is the correct query in case anyone comes across the same problem:
db.Post.findAll({
subQuery: false,
include: [
{
model: db.User,
as: 'Boosters',
where: {id: {[Op.in]: a_set_of_ids }}
}
,{
model: db.Assessment,
as: 'PostAssessments',
where: {UserId: {[Op.in]: another_set_of_ids}}
}
],
having: db.sequelize.where(db.sequelize.fn('AVG', db.sequelize.col('PostAssessments.rating')), {
[Op.eq]: 1,
}),
limit: 20,
offset: 2,
group: ['Post.id', 'Boosters.id', 'PostAssessments.id']
})
Error is with this one :
models.sequelize.col('Assessments.rating'))
Change it to
models.sequelize.col('PostAssessments.rating')) // or post_assessments.rating
Reason : You are using the alias for include as: 'PostAssessments',.

Resources