How can use LEFT JOIN at Sequelize with conditions? - mysql

Relations:
import {Topics, Users} from './model-sequelize';
Users.hasMany(Topics, {foreignKey : 'UserID'});
Topics.hasOne(Users, {foreignKey : 'UserID'});
getAllTopics (params, cb) {
const {PageIndex, PageSize} = params;
const pg = paging(PageIndex, PageSize)
Topics.findAll({
offset: pg.offset,
limit: pg.limit,
attributes: {
exclude: ['IsDelete']
},
include:[
{
model:Users,
attributes: ['UserName', 'UserID'],
required:false
}
],
where: {
IsDelete: 0
},
order: [[Sequelize.col('LastReplyTime'), 'DESC']]
}).then(res => {
cb(null, res)
}).catch(err => {
cb(err)
})
}
SQL is :
SELECT `topics`.`TopicReplies`,
`topics`.`TopicHits`,
`topics`.`TopicName`,
`topics`.`TopicLabel`,
`topics`.`LastReplyUserId`,
`topics`.`LastReplyTime`,
`topics`.`UserID`,
`topics`.`TopicContent`,
`topics`.`Plate`,
`topics`.`ID`,
`topics`.`createdAt`,
`topics`.`updatedAt`,
`user`.`ID` AS `user.ID`,
`user`.`UserName` AS `user.UserName`,
`user`.`UserID` AS `user.UserID`
FROM `topics` AS `topics`
LEFT OUTER JOIN `users` AS `user` ON `topics`.`ID` = `user`.`UserID`
WHERE `topics`.`IsDelete` = 0
ORDER BY `LastReplyTime` DESC LIMIT 20, 10;
Conditions is topics.ID = user.UserID
Question
I want using " ON topics.UserID = user.UserID ?
And now the result does not have data for the users table. What can I do ?

I think you have issue with association :
Change this:
Topics.hasOne(Users, {foreignKey : 'UserID'});
To :
Topics.belongsTo(Users, {foreignKey : 'UserID'});
And try again.

Related

Sequlize gives un Wanted info

i have two tables Products and carts and they are many to many relationship across products_carts table
i am getting specific cart and i am including Product with it so i can get the cart and their products
why i am getting products_carts with the products
my sequlize command:
const a = await Cart.findByPk(1,{
attributes: ['id'],
include: {
model: Product,
attributes: ['id'],
},
});
the sql statement :
Executing (default): SELECT `cart`.`id`, `products`.`id` AS `products.id`,
`products->products_carts`.`createdAt` AS `products.products_carts.createdAt`,
`products->products_carts`.`updatedAt` AS `products.products_carts.updatedAt`,
`products->products_carts`.`cartId` AS `products.products_carts.cartId`, `products-
>products_carts`.`productId` AS `products.products_carts.productId` FROM `carts` AS
`cart` LEFT OUTER JOIN ( `products_carts` AS `products->products_carts` INNER JOIN
`products` AS `products` ON `products`.`id` = `products->products_carts`.`productId`) ON
`cart`.`id` = `products->products_carts`.`cartId` WHERE `cart`.`id` = 1;
the ouput i am getting:
{
"cart": {
"id": 1,
"products": [
{
"id": 1,
"products_carts": { // I DONT WANT THIS TO BE SHOWN !!!
"createdAt": "2022-12-25T13:42:16.000Z",
"updatedAt": "2022-12-25T13:42:16.000Z",
"cartId": 1,
"productId": 1
}
}
]
}
}
the relation between them is ..
Cart.belongsToMany(Product, { through: PC });
Product.belongsToMany(Cart, { through: PC });
User.hasOne(Cart);
Cart.belongsTo(User);
PC stands for products_carts
through: { attributes: [] } worked for me

Fetch all records from table A where id = somvalue in B plus records which don't have id in B

I have two tables a coupons table and a coupon_city_map table.
id
coupon_code
1
OFFER20
2
OFFER10
3
OFFER50
4
OFFER40
5
OFFER90
coupon_Id
city_id
1
2
2
3
3
4
4
2
I need coupons with ids 1 4, and 5 for city_id = 2.
So It should fetch all the coupons where city_id=2 i.e. coupons with id 1 and 4
and it should also fetch coupons which don't have key in coupon_city_map i.e 5.
This is what I have tried but the query in [Op.or] is not working, and it returns all the coupons instead.
let coupons = await Coupon.findAll({
where: {
[Op.or]: [
{ '$CouponCities.city_id$': city_id },
{ '$CouponCities.coupon_id$': null },
],
...filters // other filter like is_active: true
},
include: {
model: CouponCity,
attributes: [],
},
attributes: ['id', 'coupon_code', 'discount_per', 'flat_discount', 'discount_upto', 'description', 'display'],
});
The query being generated
SELECT `Coupon`.`id`,
`Coupon`.`coupon_code`,
`Coupon`.`discount_per`,
`Coupon`.`flat_discount`,
`Coupon`.`discount_upto`,
`Coupon`.`description`,
`Coupon`.`display`
FROM `coupons` AS `Coupon`
LEFT OUTER JOIN `coupon_city_map` AS `CouponCities` ON `Coupon`.`id` = `CouponCities`.`coupon_id`
WHERE (`Coupon`.`user_id` IS NULL OR `Coupon`.`user_id` = 1)
AND `Coupon`.`is_active` = true
AND `Coupon`.`is_external` = false
AND `Coupon`.`start_date` < '2020-12-30 10:33:20'
AND `Coupon`.`expiry_date` > '2020-12-30 10:33:20';
Update
I also tried below, but still it is returning all the coupons.
let coupons = await Coupon.findAll({
// where: {
// ...filters,
// },
include: {
model: CouponCity,
required: false,
where: {
[Op.or]: [
{
zone_id: zoneId,
}, {
coupon_id: null,
},
],
},
attributes: [],
},
attributes: ['id', 'coupon_code', 'discount_per', 'flat_discount','discount_upto', 'description', 'display'],
});
...and it generates below query.
SELECT `Coupon`.`id`,
`Coupon`.`coupon_code`,
`Coupon`.`discount_per`,
`Coupon`.`flat_discount`,
`Coupon`.`discount_upto`,
`Coupon`.`description`,
`Coupon`.`display`
FROM `coupons` AS `Coupon`
LEFT OUTER JOIN `coupon_city_map` AS `CouponCities`
ON `Coupon`.`id` = `CouponCities`.`coupon_id`
AND ( `CouponCities`.`zone_id` = 1
AND `CouponCities`.`coupon_id` IS NULL )
WHERE `Coupon`.`is_active` = true
AND `Coupon`.`is_external` = false;
This is what worked for me, query is mess but it works. I am posting all the codes for better understanding for anyone interested.
Here zone is city.
{
const filters = {
start_date: {
[Op.lt]: new Date(),
},
expiry_date: {
[Op.gt]: new Date(),
},
};
if (userId) {
filters[Op.or] = [{
user_id: null,
}, {
user_id: userId,
}];
filters[Op.and] = {
[Op.or]: [
sequelize.literal('CouponZones.zone_id = 1'),
sequelize.literal('CouponZones.coupon_id IS null')
],
};
} else {
filters.user_id = null;
}
let coupons = await Coupon.findAll({
where: {
...filters,
},
include: {
model: CouponZone,
attributes: [],
},
attributes: ['id', 'coupon_code', 'discount_per', 'flat_discount', 'discount_upto', 'description', 'display'],
});
This is the query it generates.
SELECT `Coupon`.`id`,
`Coupon`.`coupon_code`,
`Coupon`.`discount_per`,
`Coupon`.`flat_discount`,
`Coupon`.`discount_upto`,
`Coupon`.`description`,
`Coupon`.`display`
FROM `coupons` AS `Coupon`
LEFT OUTER JOIN `coupon_zone_map` AS `CouponZones`
ON `Coupon`.`id` = `CouponZones`.`coupon_id`
WHERE ( `Coupon`.`user_id` IS NULL
OR `Coupon`.`user_id` = 1 )
AND ((CouponZones.zone_id = 1 OR CouponZones.coupon_id IS null))
AND `Coupon`.`is_active` = true
AND `Coupon`.`is_external` = false;
Use UNION
You can write query like below
SELECT coupons.*
FROM coupons,
coupon_city_map
WHERE coupons.id = coupon_city_map.coupon_id
AND coupon_city_map.city_id = 2
UNION
SELECT coupons.*
FROM coupons
WHERE coupons.id NOT IN(SELECT coupon_city_map.coupon_id
FROM coupon_city_map)

How to join twice a single table in sequelize using following and followers example

This code is running perfectly. i can get following and followers now i need to see that followers that i am getting is i am also following them ?
This is the question that how can i make another query/subQuery to Followers table and see that i am also following to my followers.
Follower Table
export default function(sequelize, DataTypes) {
return sequelize.define('Follower', {
_id: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
userId: {
type: DataTypes.INTEGER,
allowNull: false
},
followingId: {
type: DataTypes.INTEGER,
allowNull: false
}
});
}
Association
db.Follower.belongsTo(db.User, {as:'following', foreignKey: 'followingId'});
db.Follower.belongsTo(db.User, {as:'follower', foreignKey: 'userId'});
Query
Follower.findAll({
where: {
followingId: userId
},
attributes: ['_id'],
include: [
{
model: User,
attributes: ['fullName', 'username', '_id', 'picture'],
as: 'follower'
}
]
})
UPDATE
I have achieve desired result form row query :
SELECT F.userId, F.`followingId` , F1.`followingId` as IsFollowing , U.`fullName` FROM Followers as F
INNER JOIN Users as U ON userId = U._id
LEFT JOIN Followers as F1 On F.userId = F1.followingId
WHERE F.followingId = 142
Still struggling in sequelize.
to transform your row query into sequlize request try this:
Association
db.Follower.belongsTo(db.User, {as: 'following', foreignKey: 'followingId', sourceKey: 'userId'});
db.Follower.hasOne(db.User, {as: 'follower', foreignKey: 'userId'});
Query
Follower.findAll({
where: {
followingId: userId
},
attributes: ['userId', 'followingId'],
include: [
{
model: User,
attributes: ['fullName'],
as: 'follower',
required: true // to get inner join
},
{
model: Follower,
attributes: [['followingId', 'IsFollowing']],
as: 'following',
required: false // to get left join
}
]
});

How to write subquery with multiple where in sequelize using NodeJS

I need to execute this query using sequelize.
select * from mysqlDB.songTable where
X in (SELECT X FROM movieDB4.songTable where Y like('%pencil%') and Z='title') and
Y='tam' and Z='language';
I tried like this. but it throws some invalid value[object] error. please help to resolve this query.
const tempSQL = sequelize.dialect.QueryGenerator.selectQuery('songTable',{
attributes: ['X'],
where: {
Y: {$like: '%'+text[i]},
Z: "content_title"
}})
.slice(0,-1); // to remove the ';' from the end of the SQL
User.findAll({
where: {
X: {
$in: sequelize.literal('(' + tempSQL + ')'),
$and: {Y: lang.substring(0,3),
Z: 'language'}
}
}
})
You can use sequelize.query() to execute raw queries.
Example
return this.sequelize.query(`SELECT category_id, category_name from table_categories where category_id in (SELECT DISTINCT category_id from table_authorized_service_center_details where center_id in (SELECT center_id from table_authorized_service_center where brand_id ${condition}));`).then((results) => {
if (results.length === 0) {
reply({status: true, categories: [], forceUpdate: request.pre.forceUpdate});
} else {
reply({status: true, categories: results[0], forceUpdate: request.pre.forceUpdate});
}
}).catch((err) => {
console.log(err);
reply({status: false, message: "ISE"});
});

Nodejs JOIN query: formatting JSON output

I'm making a pretty simple RIGHT JOIN query, but I can't format the output correctly.
Here is the Query:
connection.query({sql : "SELECT users.*, rides.* FROM users RIGHT JOIN rides ON users.id = rides.id_user WHERE users.id = ?", nestTables: '_', values : [id] }, function(err, rows){
console.log(rows);
});
This is the output I have:
[ { users_id: 52,
users_firstname: 'greg', //End first table data
rides_latitude: '50.847454', //Second table data: row 1
rides_longitude: '4.358356',
},
{ users_id: 52,
users_firstname: 'greg', //Exactly the same first table data
rides_latitude: '50.9', //Second table data: row 2
rides_longitude: '4.4',
} ]
And this is the ouput I would like to have:
[ { users_id: 52,
users_firstname: 'greg',
rides : [
{
rides_latitude: '50.847454',
rides_longitude: '4.358356'
},
{
rides_latitude: '50.9',
rides_longitude: '4.4'
}
]
}]
I tried nestTables as you can see,
Wrapped for legibility:
connection.query({
sql : "SELECT \
users.users_id, \
users.users_firstname, \
rides.rides_latitude, \
rides.rides_longitude \
FROM \
users \
RIGHT JOIN rides ON users.id = rides.id_user \
WHERE \
users.id = ?",
nestTables: '_',
values : [id]
}, function (err, rows) {
var result = [], index = {};
if (err) throw err;
rows.forEach(function (row) {
if ( !(row.users_id in index) ) {
index[row.users_id] = {
users_id: row.users_id,
users_firstname: row.users_firstname,
rides: []
};
result.push(index[row.users_id]);
}
index[row.users_id].rides.push({
rides_latitude: row.rides_latitude,
rides_longitude: row.rides_longitude
});
});
console.log(result);
});