How to findAll query where value is from associated table in Sequelize? - node.js

I am using Sequelize as my ORM and I want to know the best way to achieve the desired outcome.
With the models below, how do I return an array that returns all the Books and Novels while removing duplicates that have the same author+title.
var Book = sequelize.define('Book', {
id: {
type: DataTypes.INTEGER,
allowNull: false,
autoIncrement: true,
primaryKey: true
},
title: {
type: DataTypes.STRING
},
author: {
type: DataTypes.STRING
}
//....other columns
})
var Novel = sequelize.define('Novel', {
id: {
type: DataTypes.INTEGER,
allowNull: false,
autoIncrement: true,
primaryKey: true
},
title: {
type: DataTypes.STRING
},
author: {
type: DataTypes.STRING
}
//...other different columns
})

Related

Sequelize : How to do left outer join?

My issue is related to the query,
I want to get all the products with it's related category.
And a product can have multiple Category
My Product table is
IdProduct: {
primaryKey: true,
type: Sequelize.INTEGER,
allowNull: false,
autoIncrement: true,
},
CommodityClass: {
type: Sequelize.INTEGER,
allowNull: false,
}
My Category Table is
IdProductCategory: {
primaryKey: true,
type: Sequelize.INTEGER,
allowNull: false,
autoIncrement: true
},
Name: {
type: Sequelize.STRING,
allowNull: false
}
and my productcategoryproduct table is (It contains the id of product and category)
IdProductCategory: {
type: Sequelize.INTEGER,
primaryKey: true,
allowNull: false,
references: {
model: 'ProductCategory',
key: 'IdProductCategory',
}
},
IdProduct: {
type: Sequelize.INTEGER,
primaryKey: true,
allowNull: false,
references: {
model: 'Product',
key: 'IdProduct',
}
}
I have used association as
Product.hasMany(ProductCategoryProduct);
// Product Association
ProductCategoryProduct.belongsTo(Product, { foreignKey: 'IdProduct'});
My query is
Product.findAll({
include: {
all: true
}
})
.then((results) => {
...
})
But I'm getting the error
"message":"Invalid column name 'productIdProduct'
Can someone please help me in this?

Query in join-table for N:M associations in Node JS and Sequelize

I have a classical many-to-many relationship for users which own assets: assets can be transfered to other users during their life so a window time is recorded in the AssetUser "through table",
adding STARTDATE and ENDDATE attributes.
User Table
const User = sequelize.define('User', {
ID: {
type: DataTypes.INTEGER.UNSIGNED,
allowNull: false,
primaryKey: true
},
FIRSTNAME: {
type: DataTypes.STRING,
allowNull: false
},
LASTNAME: {
type: DataTypes.STRING,
allowNull: false
}},{ timestamps: false }});
Asset Table
const Asset = sequelize.define('Asset', {
ID: {
type: DataTypes.INTEGER.UNSIGNED,
allowNull: false,
primaryKey: true
},
DESCRIPTION: {
type: DataTypes.STRING,
allowNull: false
}},{ timestamps: false }});
AssetUser Join Table
const AssetUser = sequelize.define('AssetUser', {
id: {
type: DataTypes.INTEGER.UNSIGNED,
primaryKey: true,
autoIncrement: true,
allowNull: false
},
UserID: {
type: DataTypes.INTEGER.UNSIGNED,
references: {
model: User,
key: 'ID'
}
},
AssetID: {
type: DataTypes.INTEGER.UNSIGNED,
references: {
model: Asset,
key: 'ID'
}
},
STARTDATE: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW
},
ENDDATE: {
type: DataTypes.DATE,
allowNull: true,
defaultValue: null
}},{ timestamps: false });
The models are created here:
User.belongsToMany(Asset, { through: { model: AssetUser, unique: false }, uniqueKey: 'id' });
Asset.belongsToMany(User, { through: { model: AssetUser, unique: false }, uniqueKey: 'id' });
My problem is that I want to query and find all the results where one asset, owned by one user, during a restricted period. I am not able to query the join-table but only User and Assets tables.
How can I add a "where" condition for the AssetUser table inside my query? How should I insert a STARTDATE and/or ENDDATE condition below?
Asset.findAll({
where: {
DESCRIPTION: 'Personal computer'
},
include: {
model: User,
where: {
FIRSTNAME: 'Marcello'
}
}});
Thanks for your help.
I found the solution
Asset.findAll({ where: { DESCRIPTION: 'Personal computer' }, include: { model: User, through: { where: { FIRSTNAME: 'Marcello' } } }});

How can I create an accociation to a specific key using Sequelize?

I have my models all set up, and I have a foreign key from one table to another using the tables ID. I also want to have the url property as a foreign key, but whenever I include "type: DataTypes.STRING', I get the following error
Unhandled rejection SequelizeDatabaseError: (conn=195, no: 1215, SQLState: HY000) Cannot add foreign key constraint
When I don't include the datatype, it adds the FK, but as an integer. How can I create a FK that specifically references the URL property?
Thanks
categories.belongsTo(categoriesTop, {
foreignKey: {
name: 'topCategoriesUrl',
allowNull: false,
type: DataTypes.STRING,
referencesKey: "url"
}
});
Categories_top schema
const { Sequelize, DataTypes } = require('sequelize');
const db = require('../dbconfig');
const categories_top = db.define('categories_top', {
url: {
type: DataTypes.STRING,
allowNull: false
},
title: {
type: DataTypes.STRING,
allowNull: false
},
subtitle: {
type: DataTypes.STRING,
allowNull: false
},
image: {
type: DataTypes.STRING
}
}, {
freezeTableName: true,
timestamps: false
});
module.exports = categories_top;
categories schema
const { Sequelize, DataTypes } = require('sequelize');
const db = require('../dbconfig');
const topCategories = require('./category_top');
const categories = db.define('categories', {
title: {
type: DataTypes.STRING,
allowNull: false
},
subtitle: {
type: DataTypes.STRING,
allowNull: true
},
url: {
type: DataTypes.STRING,
allowNull: false
},
image: {
type: DataTypes.STRING
}
}, {
freezeTableName: true,
timestamps: false
});
module.exports = categories;
You have to define url in category_top as a primary key or a unique constraint, like this:
const categories_top = db.define('categories_top', {
url: {
type: DataTypes.STRING,
allowNull: false,
primaryKey: true, // Either define it as a primary key
unique: true // OR as a unique constraint
},
title: {
type: DataTypes.STRING,
allowNull: false
},
subtitle: {
type: DataTypes.STRING,
allowNull: false
},
image: {
type: DataTypes.STRING
}
}, {
freezeTableName: true,
timestamps: false
});
Read more about foreign keys here.

sequelize - inner join gives an error after added a foreign key

i have these 2 models:
module.exports = function(sequelize, DataTypes) {
return sequelize.define('services_prices', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true
},
service_id: {
type: DataTypes.INTEGER(11),
allowNull: true,
references: {
model: 'services',
key: 'id'
}
},
created_at: {
type: DataTypes.DATE,
allowNull: false
},
limit: {
type: DataTypes.INTEGER(11),
allowNull: true
},
price: {
type: DataTypes.INTEGER(11),
allowNull: true
}
});
};
which is parent of this model: (services_user_prices can override services_prices )
module.exports = function(sequelize, DataTypes) {
return sequelize.define('services_user_prices', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true
},
user_id: {
type: DataTypes.INTEGER(11),
allowNull: true
},
created_at: {
type: DataTypes.DATE,
allowNull: false
},
currency: {
type: DataTypes.STRING(255),
allowNull: true
},
is_active: {
type: DataTypes.INTEGER(1),
allowNull: true,
defaultValue: '0'
},
is_trial: {
type: DataTypes.INTEGER(1),
allowNull: true,
defaultValue: '0'
},
start_date: {
type: DataTypes.DATE,
allowNull: false
},
end_date: {
type: DataTypes.DATE,
allowNull: true
},
price: {
type: DataTypes.INTEGER(11),
allowNull: true
},
bundle_price_id: {
type: DataTypes.INTEGER(11),
allowNull: true,
references: {
model: 'services_prices',
key: 'id'
}
}
});
};
when trying to join them i get an error:
EagerLoadingError: services_prices is not associated to services_user_prices!
const result= await db.services_user_prices.findOne({
where: { is_active: 1, user_id: 123 }, include:[{db.services_prices}]
});
in the db services_user_prices has foreign key to services_prices table
what am i doing wrong?
Well if you are using sequelize then you need to update your model because
by default, sequelize will be looking for foreign key starts with model name like
you have defined bundle_price_id as a foreign key for services_prices.
You need to change your column name to services_price_id then it will get fixed.
or if you want to use bundle_price_id you need to define it in your model relation as.
Model.belongsTo(models.ModelName, { foreignKey: 'your_key'} )
Please feel free if you need to ask anything else.
As complement of the above answer you need to add an identifier with as: on the association like this:
Model.belongsTo(models.ModelName, { foreignKey: 'your_key', as:'your_identifier' } )
Then when you do the include on the method you also call the identifier:
await db.services_user_prices.findOne({
where: { is_active: 1, user_id: 123 },
include:[{
model: db.services_prices
as: 'your_identifier'
}]
});
If you don't define the foreignKey field, the as field will set the column name.

How to create an associated object in Sequelize / Node.js ?

There is 2 models:
sequelize.define('Hotel', {
id: {
autoIncrement: true,
type: DataTypes.INTEGER,
primaryKey: true
},
latitude: {
type: DataTypes.DOUBLE,
allowNull: false
},
longitude: {
type: DataTypes.DOUBLE,
allowNull: false
},
title: {
type: DataTypes.STRING,
allowNull: false
},
description: {
type: DataTypes.TEXT,
allowNull: false
},
rating: {
type: DataTypes.DOUBLE,
defaultValue: 0
},
image: {
type: DataTypes.STRING
}
}, {
classMethods: {
associate: function(db) {
Hotel.hasMany(db.Comment, {
foreignKey: 'commentable_id',
scope: {
commentable: 'hotel'
}
});
}
}
});
And
sequelize.define('Comment', {
id: {
type: DataTypes.INTEGER,
primaryKey: true
},
content: {
type: DataTypes.TEXT,
allowNull: false
},
commentable: DataTypes.STRING,
commentable_id: DataTypes.INTEGER
});
How can I create associated Comment for existing Hotel instance? For example, I've tried:
hotel.addComment(request.models.Comment.create({content: 'content'}))
But it doesn't work. Please, tell me, how I can fix it? Thanks in advance!
request.models.Comment.create() is async, in other words it returns a promise that must be fullfilled before you can use the resolved value to 'feed' the addComment method.
So you should do something like
request.models.Comment.create({content: 'content'}).
then(function(comment){
return hotel.addComment(comment);
});

Resources