nodejs sequelize join query - node.js

Suppose i have two models
var A = db.seq.define('A',{
id1: { type: db.Sequelize.INTEGER},
id2: { type: db.Sequelize.INTEGER},
count: { type: db.Sequelize.INTEGER},
});
var b = db.seq.define("b",{
id1: { type: db.Sequelize.INTEGER },
id2: { type: db.Sequelize.INTEGER },
name: { type: db.Sequelize.STRING},
});
A.hasMany(B, {foreignKey: 'id1'})
B.belongsTo(A, {foreignKey: 'id1'})
A.findAll({
include: [{
model: B,
where: { B.id2: { $eq:A.id2 } }
}]
})
Its possible to make that kind of query?
How can i update my model to specify some other condition on the join sentence or should i move the check to the query where clause?
Some example will be really helpful
Thanks

Try
A.findAll({
include: [{
model: B,
where: { id2: sequelize.col('A.id2') }
}]
})
id2 will automatically reference B.

Currently Jan Aagaard Meier's answer is not fully working
I have found out that id2 is not recognized in the actual query.
For example the query
A.findAll({
include: [{
model: B,
where: { id2: sequelize.col('A.id2') }
}]
})
should recognize as inner join on 'A'.'PrimaryKey' = 'B'.'ForeignKey' and id2 = 'A'.'id2'
but somehow sequelize does not add up the left side so it ignores as
'A'.'PrimaryKey' = 'B'.'ForeignKey' and 'A'.'id2'
so query is not working
I've done the raw query that is printed when sequelize is executed and found out what was wrong.
Does anyone have an idea to solve this?
found the answer
A.findAll({
include: [{
model: B,
where: { sequelize.col('A.id2), "=", sequelize.col('B.id2') }
}]
})
This works fine for me. Hope this works well for you

Related

Nodejs sequelize hasMany issue

I've breaking my head over this sequelize to get the products questions and also to include its answers as well
const ProductQuestions = sequelize.define('product_questions', {
user: {
type: Sequelize.BIGINT
},
product: {
type: Sequelize.BIGINT
},
question: {
type: Sequelize.TEXT
}
});
ProductQuestions.associate = function(models) {
ProductQuestion.hasMany(models.product_answers,{
foreignKey: 'question',
as: 'questionId'
});
}
const ProductAnswer = sequelize.define('product_answers', {
question: {
type: Sequelize.BIGINT,
field: 'questionId'
},
answer: {
type: Sequelize.TEXT
},
user: {
type: Sequelize.BIGINT,
field: 'userId'
}
});
ProductQuestiosn.findAll({include: ['product_answers']});
for some reason when I that, the columns is wrong when the query runs
SELECT
"product_questions".*,
"product_answers"."id" AS "product_answers.id",
"product_answers"."questionId" AS "product_answers.questionId",
"product_answers"."answer" AS "product_answers.answer",
"product_answers"."userId" AS "product_answers.user",
"product_answers"."productQuestionId" AS "product_answers.productQuestionId"
FROM (
SELECT
"product_questions"."id",
"product_questions"."productId" AS "product",
"product_questions"."question",
"product_questions"."userId" AS "user",
FROM
"product_questions" AS "product_questions")
AS "product_questions"
LEFT OUTER JOIN "product_answers" AS "product_answers"
ON "product_questions"."id" = "product_answers"."productQuestionId"
not sure why is
ON "product_questions"."id" = "product_answers"."productQuestionId"
when it should be
ON "product_questions"."id" = "product_answers"."questionId"
thank you for your help
so i figured it out!
so it appears that I have to name my columns properly
for the product_answers table in my postgres database, I had the column questionId but it should be named productQuestionId. I guess it's for naming convention, i can't just name the foreign key the way i want.

Get all associated records given one match

I have two models with a one to many relation. Given that below query returns a record of ModelA (lets say it has id 1) with 3 associated ModelB (1, 2 and 3).
If I were to replace [1,2,3] in the query to just [1] it would still return the same ModelA record (with id 1) but only with the one associated ModelB (of id 1). How can I modify this query so it returns all three associated ModelB records?
ModelA.findAll({
include: [{
model: JoinTableModel,
where: {
modelB_ID: {
[Op.in]: [1,2,3]
}
},
include: [ModelB]
}]
})
Model definitions like so.
db.ModelA.hasMany(db.JoinTableModel, { foreignKey: 'modelA_ID' })
db.JoinTableModel.belongsTo(db.ModelA, { foreignKey: 'modelA_ID' })
db.ModelB.hasMany(db.JoinTableModel, { foreignKey: 'modelB_ID' })
db.JoinTableModel.belongsTo(db.ModelB, { foreignKey: 'modelB_ID' })
You can try something like this:
JoinTableModel.findAll({
where: {
modelB_ID: {
[Op.in]: [1]
}
},
include: [{
model: ModelA,
include: [{
model: JoinTableModel,
include: [ModelB]
}]
}]
})
If you add an association like this:
ModelA.belongsToMany(ModelB, { through: JoinTableModel })
then you can simplify the above query to this one:
JoinTableModel.findAll({
where: {
modelB_ID: {
[Op.in]: [1]
}
},
include: [{
model: ModelA,
include: [ModelB]
}]
})
For anyone with a similar issue as me, what I ended up doing that works for my case is modifying my initial query like this.
ModelA.findAll({
where: {
id: sequelize.literal(`
ModelA.id
IN (
SELECT modelA_ID FROM JoinTableModel
WHERE modelB_ID IN (1,2,3)
GROUP BY modelA_ID
HAVING COUNT(*) = 3
)`)
},
include: [{
model: JoinTableModel,
include: [ModelB]
}]
})
This way I could easily replace IN (1,2,3) and COUNT(*) 3 with IN (1) and COUNT(*) 1 and it would still work as intended and it doesn't break any other part of the query.
I'm still curious if anyone could solve this without using sequelize.literal in any way or if there is a more efficient way of doing it.

How to convert postgreSQL to Sequelize format

I have to try to convert my postgre sql query to orm concept using sequelize npm package, kindly guide me.
select * from "locationDepartmentMappings" as a
inner join "departments" as b on a."departmentId" = b.id
inner join "locations" as c on a."locationId" = c.id
where (
b."departmentName" like '%Accounting%' or c."locationName" like '%Accounting%'
)
limit 1;
As per below code still i have getting
error: column locationDepartmentMapping.department.departmentName does not exist
As #shivam mentioned i have tried depends mine below, can you what i need to changes,
let ldv = await LocationDepartmentModel.findAll({
include: [
{
model: LocationModel,
as: "location",
required: true,
},
{
model: DepartmentModel,
as: "department",
required: true,
}
],
where: {
$or: [
{
"department.departmentName": { like: `%${reqQueryName}%` }
},
{ "location.locationName": { like: `%${reqQueryName}%` } }
]
},
limit:1
});
Sequelize has pretty good documentation on how to write queries using the orm syntax.
To start with, the above query would look something like
Model.locationDepartmentMappings.findAll({
include: [
{
model: Model.departments
where: {departmentName: {$like: '% Accounting%'}}
},
{
model: Model.locations
where: {locationName: {$like: '% Accounting%'}}
}],
limit: 1
})
What you should consider getting to above query is
1. Learn how to create sequelize models
2. Learn Associations
3. Querying
There are a lot of great tutorials out there, which can help you get started, and are just a google search away!
Final with help got the solutions :
let ldData = await LocationDepartmentModel.findAll({
include: [
{
model: LocationModel,
as: "location",
required: true
},
{
model: DepartmentModel,
as: "department",
required: true
}
],
where: {
$or: [
{ "$department.departmentName$": { like: `%${reqQueryName}%` } },
{ "$location.locationName$": { like: `%${reqQueryName}%` } }
]
},
limit: 1
});
Courtesy for below :
#shivam answer for joining tables
#ManjulSigdel answer for where condition include table column

Sequelize: how to implement a search based on associated keywords?

I am looking to return all articles from the database associated with one or more keywords, but I am not sure there right way to go about this?
I am using Sequelize 3.x, with node.js 3.7.0.
The data model looks at follows:
const Article = sequelize.define('article', {
...
}
const Keyword = sequelize.define('keyword', {
name: Sequelize.STRING,
lang: Sequelize.STRING
}
const ArticleKeyword = sequelize.define('article_keyword', {
articleId: Sequelize.INTEGER,
keywordId: Sequelize.INTEGER
}
(Article).belongsToMany(
Keyword, { through: ArticleKeyword, as: 'keyword' });
(Keyword).belongsToMany(
Article { through: ArticleKeyword, as: 'article' });
Then the query I tried:
var keywordFilter;
if (req.body.keywords) {
var keywords = req.body.keywords);
if (typeof keywords === 'string') {
keywords = keywords.split(/ *, */);
}
keywordFilter = { name: { $in: keywords } };
}
Article.findAll({
where: {
deleted: false
},
include: [{
model: Keyword,
as: 'keywords',
where: keywordFilter,
attributes: ['name'],
through: {
attributes: []
}
}]
}).then(function(articles) {
...
});
The issue I am finding here is rather than selecting just the articles with the matching keywords it returns all the articles and then simply selects the keywords specified in the query for the results.
Can anyone suggest the right way to go about this?
Hi can you try passing
require:true
in the include block for inner join and check
Ref : https://stackoverflow.com/a/31680398/4583460

Sequelize and querying on complex relations

I'm trying to understand how best to perform a query over multiple entities using Sequelize and Node.js.
I have defined a model "User" which has a belongsToMany relation with a model "Location". I then have a model "Asset" which also has a belongsToMany relation with "Location". When I have an instance of a User I would like to fetch all Assets that are associated with Locations that the User is associated with.
I tried the following which doesn't seem to work...
user.getLocations().then(function(userLocations) { return Asset.findAll({ where: { "Locations" : { $any : userLocations } }) })
Could anyone offer any suggestions?
Try this query:
User.findById(user_id, {
include: [{
model: Location,
required: true
}]
}).then(user => Asset.findAll({
where: {
user_id: user.id,
location_id: {
$in: user.locations.map(location => location.id)
}
}
})).then(assets => {
// The rest of your logic here...
});
This was the final result...
User.findById(user_id, {
include: [{
model: Location,
as: 'Locations', // Was needed since the original relation was defined with 'as'
required: true
}]
}).then(user => Asset.findAll({
include: [{
model: Location,
as: 'Locations',
where: {
id: {
$in: user.Locations.map(location => location.id)
}
}
}]
})).then(assets => {
// The rest of your logic here...
});

Resources