Where clause for associated objects with Node and sequelize - node.js

I have Books which have an author and an editor. I'd like to query for all books with a title like '%gone% and author.name like '%paul%' - I couldn't find documentation about doing this, but I've tried various formats based on what I've googled.
Attempt using a filter on includes:
var includes = [
{"model": db.User, as: 'Author', through: {"where": {"name": { like: '%paul%'}}}}
];
var filter = { title: { like: '%gone%'}};
return Book.findAll({ include: includes, order: 'id desc', where: filter});
While the restriction on title works, the author name is ignored (no errors).
Variation without the 'through' (same result - doesn't affect resultset):
var includes = [
{"model": db.User, as: 'Author', "where": {"name": { like: '%paul%' } } }
];
And how I initiatively thought it might work (causes error):
var filter = { title: { like: '%gone%'}, 'author.name' : { like : '%paul%' } };
Any clues or pointers to documentation to help me do this??
Thanks.
Model:
var User = sequelize.define('User', {
name: {
type: DataTypes.STRING
},
...
classMethods: {
associate: function (models) {
User.hasMany(Book, { as: 'Author', foreignKey: 'author_id' });
User.hasMany(Book, { as: 'Editor', foreignKey: 'editor_id' });
},
...
}
var Book = sequelize.define('Book', {
title: {
type: DataTypes.STRING,
len: [20]
},
...
classMethods: {
associate: function (models) {
Book.belongsTo(User, { as: 'Author', foreignKey: 'author_id' });
Book.belongsTo(User, { as: 'Editor', foreignKey: 'editor_id' });
},
...

I got it to work by removing the 'as' in the User associations to Book to:
User.hasMany(Book, { foreignKey: 'author_id' });
User.hasMany(Book, { foreignKey: 'editor_id' });
Then I can filter as expected with:
var includes = [
{model: db.User, as: 'Author'},
{model: db.User, as: 'Editor'}
];
var filter = { title: { like: '%gone%'}, 'Author.name' : { like : '%paul%' } };
return Book.findAll({ include: includes, order: 'id desc', where: filter});
It helped to turn on logging of SQL statements as described here: How can I see the SQL generated by Sequelize.js?

Related

Sequelize one to Many insertion is not working?

This is my code :
const add_ticket = await db.Ticket.create({
userId,
travels: ticket.travels,
TicketInventory: {
fare: "Fare",
passenger: "passenger",
seatName: "seatName",
serviceTax: "serviceTax",
}
},
{
include: {
model: db.TicketInventory,
}})
I need to add "TicketInventory" details under "TicketInventory" table ! But it isnt adding - but rest of the details are been added to "ticket" table !
Association : Ticket HasMany TicketInventory and TicketInventory BelongsTo Ticket !
My assocaition code:
/// For Ticket Model
static associate(models) {
Ticket.hasMany(models.TicketInventory, {
foreignKey: 'ticketId',
onDelete: 'CASCADE' ,
as: 'vegetables'
});
}
};
/// For TicketInventory Model
static associate(models) {
TicketInventory.belongsTo(models.Ticket, {
foreignKey: 'ticketId',
});
}
Please help to resolve
This kind of thing...
const add_ticket = await db.Ticket.create({
userId,
travels: ticket.travels,
vegetables: [{
fare: "Fare",
passenger: "passenger",
seatName: "seatName",
serviceTax: "serviceTax",
}]
},
{
include: [{
model: db.TicketInventory,
as: "vegetables"
}]
})

Sequelize throws Error "Unable to find a valid association for model x" When Ordering By Associated Model

I have a problem with sequelize, when I want to ordering my query result by associated model, sequelize throw this error:
UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Unable to find a valid association for model, 'productLanguage'
These are my files:
**Context.js **
const Sequelize = require('sequelize');
const sequelize = new Sequelize("postgres://postgres:123456#localhost:5432/sampleDB");
module.exports = {
Sequelize: Sequelize,
sequelize: sequelize
}
User.js
const context = require('../context');
module.exports = context.sequelize.define('user', {
name: context.Sequelize.STRING,
},{
freezeTableName: true
});
Product.js
const context = require('../context');
module.exports = context.sequelize.define('product', {
slug: context.Sequelize.STRING,
price: context.Sequelize.DECIMAL(10,2),
},{
freezeTableName: true
});
ProductLanguage.js
const context = require('../context');
module.exports = context.sequelize.define('productLanguage', {
name: context.Sequelize.STRING,
},{
freezeTableName: true,
timestamps: false
});
Language.js
const context = require('../context');
module.exports = context.sequelize.define('language', {
name: context.Sequelize.STRING,
slug: context.Sequelize.STRING,
},{
freezeTableName: true
});
db.js
var context = require('./context');
var User = require('./models/User'),
Product = require('./models/Product'),
ProductLanguage = require('./models/ProductLanguage'),
Language = require('./models/Language');
// ===================== ASSOCIATIONS =====================
// user 1:m Product
Product.belongsTo(User); // product owner
User.hasMany(Product);
// Product 1:m ProductLanguage m:1 Language
ProductLanguage.belongsTo(Product);
Product.hasMany(ProductLanguage);
ProductLanguage.belongsTo(Language);
Language.hasMany(ProductLanguage);
module.exports = {
Sequelize: context.Sequelize,
sequelize: context.sequelize,
models: {
Product: Product,
User: User,
ProductLanguage: ProductLanguage,
Language: Language
}
}
and finally this is my query
app.get('/', async (req, res, next)=>{
var result = await db.models.User.findAll({
include:[
{
model: db.models.Product,
attributes: ['price'],
include: [
{
model: db.models.ProductLanguage,
attributes: ['name'],
include: [
{
model: db.models.Language,
attributes: ['name'],
}
]
}
]
}
],
order:[
[db.models.ProductLanguage, 'name', 'desc']
],
attributes: ['name']
});
res.send(result);
});
The query work fine without "order" part, so I think the problem should be one on these :
Something is wrong on this part: [db.models.ProductLanguage, 'name', 'desc']
Something is wrong on association definitions
Note: I've searched on youtube and stackoverflow and sequelize documentation over 4 days but nothing found.
I use these dependencies:
"express": "^4.16.2",
"pg": "^6.4.2",
"pg-hstore": "^2.3.2",
"sequelize": "^4.32.2"
I've found the solution.
I must put all associated model into order, so the correct query is:
order:[
[db.models.Product, db.sequelize.models.ProductLanguage, 'name', 'desc']
],
The full query must be:
var result = await db.models.User.findAll({
include:[
{
model: db.models.Product,
attributes: ['price'],
include: [
{
model: db.models.ProductLanguage,
attributes: ['name'],
include: [
{
model: db.models.Language,
attributes: ['name'],
}
]
}
]
}
],
order:[
[db.models.Product, db.sequelize.models.ProductLanguage, 'name', 'desc']
],
attributes: ['name']
});
I hope this will be helpful for others.
Those who still won't get the result, try this syntax -
order:[[{ model: db.models.ProductLanguage, as: 'language_of_product' } , 'name', 'desc']]
In addition to Moradof's answer, it's important to note that if you specify an alias for your included model, then you must also specify the alias in the order statement.
Building on the previous example, we get:
var result = await db.models.User.findAll({
include:[
{
model: db.models.Product,
as: 'include1',
attributes: ['price'],
include: [
{
model: db.models.ProductLanguage,
as: 'include2',
attributes: ['name'],
include: [
{
model: db.models.Language,
attributes: ['name'],
}
]
}
]
}
],
order:[
[{ model: db.models.Product, as: 'include1' },
{ model: db.sequelize.models.ProductLanguage, as: 'include2' },
'name',
'desc']
],
attributes: ['name']
});
Note that because I named the Product as include1 in the include statement, I also had to name it as include1 in the order statement.
order:[
[{ model: db.models.Product, as: 'include1' },
{ model: db.sequelize.models.ProductLanguage, as: 'include2' },
'name',
'desc']
After using this sequlizer is creating this in query. ORDER BY ``.name DESC LIMIT 10;
So how can I pass the table alias before name.

Sequelize Eager Loading Error

I'm getting an issue where include in my query isn't working, and I can't figure out why. I have two models: Question and Suggestion.
Question:
var Question = sequelize.define('Question', {
}, {
classMethods: {
associate: function (models) {
// associations can be defined here
Question.belongsTo(models.User, {
as: 'askerId',
foreignKey: 'askerId'
})
Question.belongsTo(models.User, {
as: 'winnerId',
foreignKey: 'winnerId'
})
Question.hasMany(models.Suggestion)
Question.hasMany(models.TagQuestion)
}
}
})
Suggestion:
var Suggestion = sequelize.define('Suggestion', {
text: DataTypes.STRING
}, {
classMethods: {
associate: function (models) {
// associations can be defined here
Suggestion.belongsTo(models.Question, {
foreignKey: 'questionId',
as: 'question'
})
Suggestion.belongsTo(models.User)
Suggestion.hasMany(models.Vote)
}
}
})
And my attempted query is here:
Question.findAll({
include: [{
model: models.Suggestion
}]
})
But I keep getting the error: SequelizeEagerLoadingError: Suggestion is not associated to Question!
Why are they not associated? They are in my database (based on my migration that I wrote). And how should I set up my associations if I am currently doing it incorrectly? I've looked at other people with this issue and not been able to figure out why my associations are wrong.
I ran into this error because I had a bad syntax. I was using
include: {
model: db.modelOne,
model: db.modelTwo
}
without the brackets []. Including it solved the error.
Anyway, the mentioned docs give this much cleaner option to include all the foreign models recursively:
User.findAll({ include: [{ all: true, nested: true }]});
Please check out your init-models.js, code like this:
question.hasMany(suggestion, { as: 'suggestion', foreignKey: 'questionId'});
suggestion.belongsTo(question, { as: 'question', foreignKey: 'questionId'});
is exist ?
from
"sequelize": "^6.6.2"
Sequelize no longer supports classMethods. classMethods and instanceMethods are removed.
Previous:
const Model = sequelize.define('Model', {
...
}, {
classMethods: {
associate: function (model) {...}
},
instanceMethods: {
someMethod: function () { ...}
}
});
New:
const Model = sequelize.define('Model', {
...
});
// Class Method
Model.associate = function (models) {
...associate the models`enter code here`
};
Refrence: http://docs.sequelizejs.com/manual/tutorial/upgrade-to-v4.html#breaking-changes

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

How can I make an order with n:m associations?

I'm using sequelize.js for ORM, and I have some questions while I use it.
Models looks like this
var Keyword = db.define('keyword', {
name: db.STRING,
});
var KeywordSearchableMap = db.define('keyword_searchable_map', {
keyword_id: db.INTEGER,
searchable: db.STRING,
searchable_id: db.STRING,
score: db.STRING,
});
var Searchable = db.define('searchable') {
name: db.STRING,
});
Keyword.belongsToMany(Searchable, {
through: {
model: KeywordSearchableMap,
},
foreignKey: 'keyword_id'
});
Searchable.belongsToMany(Keyword, {
through: {
model: KeywordSearchableMap,
},
foreignKey: 'searchable_id'
});
And I want to get 'Searchable' things by Keyword.getSearchables() order by 'score' field in 'KeywordSearchableMap'
Is there any methods to get sorted searchable objects?

Resources