Sequelize select only chosen attributes - mysql

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

Related

Eager load multiple and nested associations

I have three models, A, B and C, where:
A.hasMany(B);
B.belongsTo(A);
B.hasMany(C);
C.belongsTo(B);
I'm querying like this:
await A.findOne({
where: { id: id },
include: [
{
model: B,
},
],
});
How can I return the C objects that belongs to B when querying A?
In the end found the solution in the comments of another question.
I need to pass the include with a array like this [{ all: true, nested: true }], I end up having something like this:
await A.findOne({
where: { id: id },
include: [{ all: true, nested: true }],
});
I didn't tested what happens when it loops and also didn't found the docs about it, if a good soul find it feel free to comment it.
Edit:
Nested includes also works:
await A.findOne({
where: { id: id },
include: [
{
model: B,
include: [
{
model: C,
},
],
},
],
});

How to do where condition on include relation in Loopback

I want to get the result with include relation with where condition on include model.
return this.htcApi.find({
include: [
{
relation: 'nmos',
scope: {
include: 'countries',
},
},
],
where: { name:'Welcome', "nmos.name":'agile'}
});
This where is condition work for name of htc model not for noms module.
I want query like
Select htc.*, nmos.* FROM htc LEFT JOIN nmos ON nmos.id = htc.n_id where htc.name = 'abc' and nmos.name = 'abc';
How can add where condition on the "relation" table?
Simply you need to add where clause in 'scope' object which lies inside the 'include' object. So the code would be like :
return this.htcApi.find({
include: [
{
relation: 'nmos',
scope: {
include: 'countries',
where:{name:'agile'}
},
},
],
where: { name:'Welcome'}
});
In your query, you just need to add the property where within the scope property, like this:
return this.htcApi.find({
include: [
{
relation: 'nmos',
scope: {
include: 'countries',
where: {
and [
{ id: htc.n_id },
{ name: 'abc' },
],
},
},
},
],
where: { name: 'abc' }
});
This should return the htcApi objects named 'abc' with the related nmos objects that have the name 'abc' and the id 'n_id'.

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....

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