sequelize Not unique table/alias - mysql

Dears am getting a problem because included join a table throw another table then i include it immediately
The (User) table should return provider name if i access the (User) table through (Provider)
if included the (User) table imdditly that's mean getting the customer name
but i get the below error
ER_NONUNIQ_TABLE: Not unique table/alias: 'Provider.User'
Code :
models.Order.findOne({
where: {
id: req.params.id
},attributes: ['orderStatus','id','serviceId','providerId','orderDescription',"orderScheduledDate",'userLat','userLng','createdAt'],
include: [
{
model: models.Provider,
attributes: ['id','userId'],
include : [{
model : models.User,
attributes: ['firstName','lastName','phoneNumber']
},{
model : models.User,
attributes: ['phoneNumber']
}]
}
]
})

If you want to include same model twice , you need to assign an alias to the relation-ship/association :
Provider.belongsTo/haveMany/any...(User, {as: 'ProviderUser'}); //<------ HERE
Provider.belongsTo/haveMany/any...(User, {as: 'User'}); //<------ HERE
include: [{
model: models.Provider,
attributes: ['id', 'userId'],
include: [{
model: models.User,
as : 'User' //<---------- HERE
attributes: ['firstName', 'lastName', 'phoneNumber']
}, {
model: models.User,
as : 'ProviderUser' //<---------- HERE
attributes: ['phoneNumber']
}]
}]

Related

Sequelize: Deep population association join query

I have a three tables as shown in this diagram https://dbdiagram.io/d/602fa54dfcdcb6230b2095e5
I would like to get my result as below json.
"data": [{
"products": {
"id": 12,
"product_catalog_id": 1,
"product_catalog": {
"id": 1,
"full_name": "Test"
}
"product_images": {
"id": 11,
"product_catalog_id": 1
}
}
}]
For that I have applied like below association rules of sequelize ORM
ProductModel.belongsTo(ProductCatalogModel, {foreignKey: 'product_catalog_id', targetKey: 'id', as : 'products' })
ProductImagesModel.belongsToMany(ProductCatalogModel , {through: ProductModel, foreignKey: 'product_catalog_id', targetKey: 'id', as :'product_images' });
ProductCatalogModel.belongsToMany(ProductImagesModel , {through: ProductModel, foreignKey: 'product_catalog_id', targetKey: 'id', as :'product_images' });
To find the result have applied below query.
var associations: Array<FindOptions | any> = [];
associations.push({
model: ProductModel,
as: 'products',
include: [{
model: ProductImagesModel,
as: 'product_images,
}]
})
var execute = await this.model.findAll()
return execute;
But instead of mapping the productImages model with productCatalog model it is going to map it with products table model.
I have also tries with the sequelize.literal into ProductImagesModel but that is throwing me an error like
"Include unexpected. Element has to be either a Model, an Association or an object."
associations.push({
model: ProductModel,
as: 'products',
include: [{
// model: ProductImagesModel,
// as: 'product_images,
include: [sequelize.literal(`(
SELECT id, product_catalog_id FROM product_images AS product_images
WHERE product_images.product_catalog_id IN (1)
)`)]
}]
})
I think it is simpler than you are making it. Try following this pattern:
const pugs = await Pug.findAll({ include: [{ model: Owner }] })
This should result in a list of pugs with an owner attribute with the owner attributes nested inside.

Sequelize select only chosen attributes

I am using MySQL database, when I am doing:
models.modelA.findAll({
attributes: [
['modelA.id','id']
],
raw: true,
include:
[
{
model: models.modelB,
required: true
}
]
}).then(function (tenants) {
});
Nevertheless that I've selected only id, Sequelize is retrieving all attributes, from related table as well so I'm getting {id, ... All attributes here}.
How I can prevent this? Sometimes I want to select only 2/3 columns and Sequelize is always selecting all of them what is not efficient.
You can do something like the following
models.modelA.findAll({
attributes: [
'id'
],
raw: true,
include:
[
{
model: models.modelB,
attributes: ['fieldName1', 'fieldName2'], // Add column names here inside attributes array.
required: true
}
]
}).then(function (tenants) {
});
You can try sending empty array as attributes to exclude them:
models.modelA.findAll({
attributes: [
['modelA.id','id']
],
raw: true,
include:
[
{
model: models.modelB,
attributes: [],
required: true
}
]
}).then(function (tenants) {
});

Exclude primary key attributes from a sequelize query

I have a sequelize query from multiple tables inner joined together. I need to group them by on a nested include model but the sequelize query throws the primary key every time, even if I mention the attributes as: attributes:[].
However attributes:[] is working for nested include models.
You can exclude any attributes by passing an exclude array into the attributes option:
MyModel.findAll({
attributes: {exclude: ['some_field']}
});
For included models use attributes: ['prop_name']
Remember include/exclude will not affect nested tables use through: { attributes:[]}
Model.addScope('scope_name', {
attributes: ['id', 'name'],
include: [
{
model: models.role,
as: 'roles',
attributes: ['name'],
through: {
attributes: []
}
}
]
More details can be found here: https://github.com/sequelize/sequelize/issues/4074#issuecomment-153054311
I want to add that you can explicitly list the attributes you want and that they work on nested inner joins as follows:
const my_model = await MyModel.findById(id, {
include: [
{
model: AnotherModel,
attributes: [ 'displayName', 'email' ] // only these attributes returned
},
{ model: YetAnotherModel,
include: [{
model: AnotherModel,
attributes: [ 'id', 'displayName', 'email' ]
}]
}
]
})
Your returned Object should look like:
{
// ...MyModel attributes
,
AnotherModel: {
displayName: '...',
email: '...',
},
YetAnotherModel: {
// ...YetAnotherModel's attributes
,
AnotherModel: {
id: '...',
displayName: '...',
email: '...',
}
}
}

Sequelize include even if it's null

I am using Sequelize express with Node.js as the backend, some data from my sequelize I need to include to another table but some of these data is null so the whole result I’m getting is null.
Question: how can I return some data if data it's available and return the other null if not data is there
router.get("/scheduled/:id", function(req, res, next) {
models.Order.findOne({
where: {
id: req.params.id
},
attributes: ['orderStatus', 'id', 'serviceId', 'orderDescription', 'orderScheduledDate'],
include: [{
model: models.User,
attributes: ['firstName', 'phoneNumber']
}]
}).then(function(data) {
res.status(200).send({
data: data,
serviceName: data["serviceId"]
});
});
});
I want: the result should return null if there is no user for the order and return order details and user when it is null.
However, a where clause on a related model will create an inner join and return only the instances that have matching sub-models. To return all parent instances, you should add required: false for more detail check nested-eager-loading
var users = require('./database/models').user;
models.Order.findOne({
where: {
id: req.params.id
},attributes: ['orderStatus','id','serviceId','orderDescription','orderScheduledDate'],
include: [
{model: users,required: false,
attributes: ['firstName','phoneNumber']
}
]
}).then(function(data) {
res.status(200).send({data : data,serviceName : data["serviceId"]});
});
You can add attribute required: false,
const result = await company.findAndCountAll({
where: conditions,
distinct: true,
include: [
media,
{
model: tag,
where: tagCond,
},
{ model: users, where: userCond, attributes: ['id'] },
{
model: category_company,
as: 'categoryCompany',
where: categoryCond,
},
{ model: media, as: 'logoInfo' },
{ model: city, as: 'city' },
{
model: employee,
as: 'employees',
required: false,
include: [{
model: media,
as: 'avatarInfo',
}],
where: {
publish: {
[Op.ne]: -1,
},
},
},
],
order: [['createdAt', 'DESC']],
...paginate({ currentPage: page, pageSize: limit }),
});

Sequelize Query - Finding records based on many-to-many table and parent table

Given the following sequelize models:
var User = db.define('user', {
name: Sequelize.STRING
});
var Group = db.define('group', {
name: Sequelize.STRING,
public : { type: Sequelize.BOOLEAN, defaultValue: true }
});
Group.belongsToMany(User, { as: 'specialUsers', through: 'user_groups', foreignKey: 'group_id' });
User.belongsToMany(Group, { through: 'user_groups', foreignKey: 'user_id' });
How would I go about finding the Groups for a through the Groups model where the Groups returned should be those where the user has a record in the many to many table -- or -- the group is a public group?
I've tried something like this:
return Group.findAll({
attributes: ['name', 'public'],
include: [{
model: User,
as: 'specialUsers',
where: {
$or : [
{name: 'Neill'},
Sequelize.literal('"group"."public" = true')
]
}
}]
});
return Group.findAll({
attributes: ['name', 'public'],
include: [{
model: User,
as: 'specialUsers',
}],
where: {
$or : {
'$users.name$": 'Neill',
public: true
}
}
});
Should work if you are on a fairly recent version. Note that I moved the where out of the include