Request with 2 many to many with sequelize (merge result) - javascript

I would like to know how can I "merge" the result to get result from 2 tables.
Currently I have 3 tables :
posts [id, title...]
feeds [id, fk_people_id, fk_post_id]
posts_peoples [id, fk_people_id, fk_post_id]
I would like to return the posts where people is present in feeds table and posts_peoples table.
When I run this request, I have only the post where people is present in feeds table :
// Request
const resultRequest = await db.Post.findAll({
include: [
{
model: db.Feed,
as: "Feed",
where: {
fk_people_id: 2,
},
},
],
})
When I run this request, I have only the post where people is present in posts_peoples table :
// Request
const resultRequest = await db.Post.findAll({
include: [
{
model: db.PostPeople,
as: "PostPeople",
where: {
fk_people_id: 2,
},
},
],
})
When I add feeds and posts_peoples, it doesn't work.
// Request
const resultRequest = await db.Post.findAll({
include: [
{
model: db.Feed,
as: "Feed",
where: {
fk_people_id: 2,
},
},
{
model: db.PostPeople,
as: "PostPeople",
where: {
fk_people_id: 2,
},
},
],
})
The result is an empty array.

Add required: false to your includes to generate SQL with a LEFT JOIN to include results from both tables.
// Request
const resultRequest = await db.Post.findAll({
include: [{
model: db.Feed,
as: "Feed",
where: {
fk_people_id: 2,
},
required: false,
},
{
model: db.PostPeople,
as: "PostPeople",
where: {
fk_people_id: 2,
},
required: false,
}],
})

Related

Two foreign key one table in sequalize

I have Offers table 2 row exit_customs and destination_customs. This 2 row has a my Customs table id. My problem is how to two(exit_customs and destination_customs) foreign key one(Customs) table?
Here is my list query function
router.post('/api/logistic/offers/get-offers', async (req, res) => {
const {limit, page, sortColumn, sortType, search} = req.body;
const total = await Offers.findAll();
const offersList = await Offers.findAll({
limit: limit,
offset: (page - 1) * limit,
order: [
[sortColumn, sortType]
],
where: {
[Op.or]:[
{
offers_no: {
[Op.substring]: [
search
]
}
},
{
agreement_date: {
[Op.substring]: [
search
]
}
},
{
routes: {
[Op.substring]: [
search
]
}
},
{
type_of_the_transport: {
[Op.substring]: [
search
]
}
},
]
}
});
res.json({
total: total.length,
data: offersList
});
})
this solution connects the two data in the first table to the id in the other table as you want. hope it helps
Offers.belongsTo(Customs, {as: 'Exit_customs', foreignKey: 'exit_customs'});
Offers.belongsTo(Customs, {as: 'Destination_customs', foreignKey: 'destination_customs'});
router.post('/api/logistic/offers/get-offers', async (req, res) => {
const {limit, page, sortColumn, sortType, search} = req.body;
const total = await Offers.findAll();
const offersList = await Offers.findAll({
limit: limit,
offset: (page - 1) * limit,
order: [
[sortColumn, sortType]
],
where: {
[Op.or]: [
{
offers_no: {
[Op.substring]: [
search
]
}
},
{
agreement_date: {
[Op.substring]: [
search
]
}
},
{
routes: {
[Op.substring]: [
search
]
}
},
{
type_of_the_transport: {
[Op.substring]: [
search
]
}
},
]
},
include: [{
model: Customs,
as: 'Exit_customs'
}, {
model: Customs,
as: 'Destination_customs'
}]
});
res.json({
total: total.length,
data: offersList
});
})
You can give foreign key using "as" keyword, please add below code in your Offers models file
static associate(models) {
models.Offers.belongsTo(models.Customs, {
foreignKey: "exit_customs",
as: "exitCustomsDetails",
});
models.Offers.belongsTo(models.Customs, {
foreignKey: "destination_customs",
as: "destinationCustomsDetails",
});
}

Sequelize filter the included tables by where

I am trying to findAll records included nested tables, but did not understand how could I filter included tables by where clause. Here are the words:
const players = await PlayerService.findPlayers({
attributes: { exclude: ['password'] },
include: [
{ all: true },
{
model: Team,
as: 'captainTeams',
attributes: {exclude: ['createdAt', 'updatedAt']}
},
{
model: Team,
as: 'teams',
where: { type: 1 },
required: true,
through: {attributes: []},
attributes: {exclude: ['createdAt', 'updatedAt']}
}
]
})
Here is the result:
If I delete where and required from including Team clause, here is the result:
I would like to filter teams.type=2. Could you help me ?

Sequelize querying both parent model and included model using [Op.or]

I want to findAll Bookings where the booking has been paid.
A legacy booking has been paid if the paymentAuthorised: boolean attribute on the Booking table is true.
A new booking has been paid if the paymentAuthorised: boolean attribute on the Payment table is true and type: string attribute on the Payment table is 'booking'.
When I perform the following query it returns an error saying payments.paymentAuthorised not found.
const bookings = await db.Booking.findAll({
include: [
{
model: db.Payment,
as: "payments",
},
],
where: {
[Op.or]: [
{
paymentAuthorised: { [Op.eq]: true },
},
{
"$payments.paymentAuthorised$": { [Op.eq]: true },
"$payments.type$": { [Op.eq]: "booking" },
},
],
},
order: [["dateTime", "asc"]],
});
I worked this issue out in the end by logging the generated SQL. You need to add the following parameter: subQuery: false. This is so it generates an SQL query which includes the joins before the where.
const bookings = await db.Booking.findAll({
include: [
{
model: db.Payment,
as: "payments",
},
],
where: {
[Op.or]: [
{
paymentAuthorised: { [Op.eq]: true },
},
{
"$payments.paymentAuthorised$": { [Op.eq]: true },
"$payments.type$": { [Op.eq]: "booking" },
},
],
},
subQuery: false,
order: [["dateTime", "asc"]],
});

How to write custom where condition raw query?

How to write this sql query as sequelize query?
select * from chats where senderId + receiverId = 25
I want to use above query where condition in where clause of sequelize which is written below.
const options = {
page: req.params.pageNo, // Default 1
paginate: 25, // Default 25
order: [['id', 'DESC']],
include: [
{
model: db.users,
required: true,
as: 'senderUser',
attributes: ['id', 'name', 'email', 'mobileNumber', 'profilePic'],
},
{
model: db.users,
required: true,
as: 'receiverUser',
attributes: ['id', 'name', 'email', 'mobileNumber', 'profilePic'],
},
],
where: {
//here i need condition
},
};
db.chats
.paginate(options)
.then(result => {
let apiData = { pages: result.pages, total: result.total, chats: result.docs };
return _RL.apiResponseOk(res, 'Messages', apiData);
})
.catch(error => {
console.log(error);
return _RL.serverError(res);
});
You'll have to write aggregate query
await Chats.aggregate([
{
$addFields:{
'total':{$add:['$senderId','$receiverId']}
}
},
{
$match:{
'total':{$eq:25}
}
}
])
I'm assuming both senderId & receiverId are Numbers

How to query sequelize model by association, but include all associated objects?

Trying to query by all association's attribute, but get all associations
# FAQs: { id: 1, name: 'How to do it?' }, { id: 2, name: 'How to FIX it?' }
# tags: { id: 1, slug: 'api' }, { id: 2, slug: 'beta' }
# taggings: { id: 1, faqId: 1, mainEntityId: 1, mainEntityType: 'faq' }, { id: 2, faqId: 1, mainEntityId: 2, mainEntityType: 'faq' }
const query = { slugs: ['api'] }
const foundFAQs = await this.models.FAQ.findAll({
where: {
'$taggings.tag.slug$': { $in: query.slugs },
},
include: [{
model: this.models.Tagging,
as: "taggings",
include: [{
model: this.models.Tag,
as: 'tag',
}],
}],
})
My model definition:
models.Tagging.belongsTo(models.Tag, { as: 'tag', onDelete: 'cascade' });
models.Tag.hasMany(models.Tagging, { as: 'taggings', onDelete: 'cascade' });
models.Tag.belongsToMany(models.FAQ, { through: models.Tagging, as: 'faqs' });
models.FAQ.hasMany(models.Tagging, { as: 'taggings', onDelete: 'cascade' });
models.FAQ.belongsToMany(models.Tag, { through: models.Tagging, as: 'tags' });
What do you expect to happen?
I want to get all FAQs what has associated TAG api and have all its tags.
Object:
{
id: 1,
name: 'How to do it?',
tags: [
{ id: 1, slug: 'api' },
{ id: 2, slug: 'beta' }
]
}
What is actually happening?
Query returns object:
{
id: 1,
name: 'How to do it?',
tags: [
{ id: 1, slug: 'api' }
]
}
Output
SELECT \"faq\".\"id\", \"faq\".\"name\", \"faq\".\"bankId\", \"faq\".\"priority\",
\"faq\".\"publishedLocales\", \"faq\".\"createdAt\", \"faq\".\"updatedAt\", \"taggings\".\"id\"
AS \"taggings.id\", \"taggings\".\"tagId\" AS \"taggings.tagId\", \"taggings\".\"locked\"
AS \"taggings.locked\", \"taggings\".\"sdkId\" AS \"taggings.sdkId\", \"taggings\".\"guideId\"
AS \"taggings.guideId\", \"taggings\".\"newsId\" AS \"taggings.newsId\", \"taggings\".\"faqId\"
AS \"taggings.faqId\", \"taggings\".\"apiId\" AS \"taggings.apiId\", \"taggings\".\"createdAt\"
AS \"taggings.createdAt\", \"taggings\".\"updatedAt\" AS \"taggings.updatedAt\", \"taggings->tag\".\"id\"
AS \"taggings.tag.id\", \"taggings->tag\".\"name\" AS \"taggings.tag.name\", \"taggings->tag\".\"slug\"
AS \"taggings.tag.slug\", \"taggings->tag\".\"tagType\" AS \"taggings.tag.tagType\", \"taggings->tag\".\"mainEntityId\"
AS \"taggings.tag.mainEntityId\", \"taggings->tag\".\"createdAt\"
AS \"taggings.tag.createdAt\", \"taggings->tag\".\"updatedAt\"
AS \"taggings.tag.updatedAt\" FROM \"faqs\" AS \"faq\" INNER JOIN \"taggings\"
AS \"taggings\" ON \"faq\".\"id\" = \"taggings\".\"faqId\" LEFT OUTER JOIN \"tags\"
AS \"taggings->tag\" ON \"taggings\".\"tagId\" = \"taggings->tag\".\"id\" WHERE \"faq\".\"bankId\" = 'bank.csas'
AND \"taggings->tag\".\"slug\" IN ('faq') ORDER BY \"faq\".\"priority\" DESC;
Dialect: postgres
Dialect version: pg#^6.1.0
Database version: PostgreSQL 10.1
Sequelize version: 4.23.2
Tested with the latest release: No (4.23.2)
Node: 8.6.0
I am not sure if it is a bug or I'm doing something wrong.
Thanks
You're looking to include all related data for each record, but filter those records on that related data. You're going to want to get Sequelize to generate SQL similar to:
SELECT "faq"."id", ....
FROM "faqs" AS "faq"
INNER JOIN "taggings" AS "taggings" ON "faq"."id" = "taggings"."faqId"
LEFT OUTER JOIN "tags" AS "taggings->tag" ON "taggings"."tagId" = "taggings->tag"."id"
LEFT OUTER JOIN "tags" AS "taggings->tagdata" ON "taggings"."tagId" = "taggings->tagdata"."id"
WHERE "faq"."bankId" = 'bank.csas' AND "taggings->tag"."slug" IN ('faq')
ORDER BY "faq"."priority" DESC;
Something like this might work:
const foundFAQs = await this.models.FAQ.findAll({
where: {
'$taggings.tag.slug$': { $in: query.slugs },
},
include: [{
model: this.models.Tagging,
as: "taggings",
include: [{
model: this.models.Tag,
as: 'tag',
},{
model: this.models.Tag,
as: 'tagdata',
}],
}],
})
The idea here is that you're performing a join on which you are filtering, and then another join to get the extra records for the filtered rows.
This worked for me today -- nested includes:
getReferralPlanForThisCode(parent, args, context) {
let {referralCode} = args;
return Promise.resolve()
.then(() => {
let referralPlan = connectors.ReferralPlans.findAll({
include: [{
model: connectors.ReferralCodes,
where: {unique_referral_code: referralCode},
include: [{
model: connectors.epUserData, as: 'referrer',
}],
}],
})
return referralPlan;
})
.then(referralPlan => {
return referralPlan;
})
.catch((err) => {
console.log(err);
});
}

Categories