Exclude primary key attributes from a sequelize query - mysql

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: '...',
}
}
}

Related

How to limit includes on a belongsToMany association in Sequelize JS?

I currently have the following models in Sequelize:
Product
and
ProductList.belongsToMany(models.Product, { as: 'products', through:
sequelize.models.ProductListProduct, foreignKey: 'productListId'});
and the pivot, ProductListProduct
I am currently trying to get a series of productList to show on my homepage,
and would need to limit the returned products to a certain value (6 in this case):
let productLists = await ProductList.findAll({
where: {
slug: ['recommended', 'new_and_promos']
},
include: [{
model: Product,
as: 'products',
include: ['attributes', 'images'],
where: {
active: true
}
}],
order: [
[
'products', ProductListProduct, 'position', 'ASC'
]
]
})
This is the current fetch, however if I add a limit to the include, it tells me that only hasMany can have {separate: true} ;
To recap, what I'm trying to achieve is to return n ProductList, each with just m Product attached.
Managed to get it working like this, doesn't look ideal but it does the job:
let productLists = await ProductList.findAll({
where: {
slug: ['recommended', 'new_and_promos']
},
include: [{
model: Product,
as: 'products',
include: ['attributes', 'images'],
where: Sequelize.literal('`products->ProductListProduct`.`position` < 8')
}],
order: [
[
'products', ProductListProduct, 'position', 'ASC'
]
]
})

Sequelize - Include all children if any one matches

I have two entities, Post and Tag, I am trying to query for all posts that have any one tag passed to the where clause. In addition, I want to include ALL the tags for the final set of Posts.
The association is defined as so
Post.belongsToMany(
models.tag,
{
through: 'post_tag'
}
);
My query is like so
models.post.findAll({
limit: 20,
offset: 0,
attributes: [
'id',
'name'
],
include: [{
model: models.tag,
attributes: ['name'],
where: {
name: {
[Op.in]: ['tagNameHere']
}
}
}],
where: [{
active: {
[Op.not]: 'False'
}
}],
order: [ ['name', 'ASC'] ]
})
It does work, but the included tags array is ONLY that one specified within the Op.in. I want ALL the tags to be included
Any better way of going about it?
One approach is to make two passes: 1) find posts that have particular tag, 2) find all tags for those posts. You need a third association to make this happen:
models.post.belongsToMany(models.tag, {through: models.postTag, foreignKey: 'post_id'} );
models.tag.belongsToMany (models.post,{through: models.postTag, foreignKey: 'tag_id' });
models.post.hasOne(Post, {
foreignKey: {name: 'id'},
as: 'selfJoin'
});
Now, identify posts that have particular tag (or tags)
models.post.addScope('hasParticularTag',
{
attributes: ['id'],
include: [
{
model: models.tag,
through: models.postTag,
attributes: [],
where: {name: 'TAG-YOU-WANT'} // your parameter here...
}]
});
Finally, list selected posts and all their tasks...
models.post.findAll({
attributes: ['id','name'],
include: [
{ // ALL tags
model: models.tag,
through: models.postTag,
attributes: ['name']
},
{ // SELECTED posts
model: models.post.scope('hasParticularTag'),
required: true,
as: 'selfJoin', // prevents error "post isn't related to post"
attributes: []
}]
})
HTH....

sequelize Not unique table/alias

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']
}]
}]

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) {
});

FindAll WHERE using include with alias field in sequelize

How to perform FindAll with WHERE using alias include association
Now I have this code :
Photobook.findAndCountAll({
include: [
{
attributes: ['full_name'],
as: 'layouter_name',
model: UserModel,
},
{
attributes: ['full_name'],
as: 'current_pic',
model: UserModel,
}
],
where:{
{
'$current_pic.full_name$' : {
$like: '%name%'
}
}
}
});
It doesn't work since the Photobook model don't have current_pic.full_name field. I just want to search the current_pic association instead of layouter_name association.
How to perform something like that ?
Try this:
Photobook.findAndCountAll({
include: [
{
attributes: ['full_name'],
as: 'layouter_name',
model: UserModel,
},
{
attributes: ['full_name'],
as: 'current_pic',
model: UserModel,
where: {
full_name: {
$like: '%name%'
}
},
required: true
}
]
});
You can give where condition in the include array itself. required: true ensures that the JOIN is treated as INNER JOIN