I have Roles Model, Member Model as a parent model, and MemberRole as a child
Role.belongsToMany(models.Member, {foreignKey: 'roleId', through: models.MemberRole});
Role.hasMany(models.MemberRole, {foreignKey: 'roleId', as: 'roleMembers'});
Currently, it is giving count irrespective of Member Status. I want to get Count of memberRoles if Member has Active status
subQuery: false,
where: {accountId: accountId},
attributes: {
include: [
[Sequelize.literal('COUNT(DISTINCT("roleMembers"."id"))'), 'assignedMemberCount'],
[Sequelize.literal('COUNT(DISTINCT("roleGroups"."id"))'), 'assignedGroupCount'],
]
},
include: [{
model: MemberRole,
as: 'roleMembers',
attributes: [],
required: false
},
order: [['name', 'ASC']],
group: ['Role.id'],
limit: options.limitCount,
offset: options.skipCount
The most correct way would be to use subqueries especially when you use limit and offset for the main model:
subQuery: false,
where: {accountId: accountId},
attributes: {
include: [
[Sequelize.literal('SELECT COUNT("roleMembers"."id") FROM roleMembers where roleMembers.roleId=roles.id'), 'assignedMemberCount'],
]
},
order: [['name', 'ASC']],
limit: options.limitCount,
offset: options.skipCount
I didn't indicate assignedGroupCount because I didn't see include for roleGroups. You can add it using the assignedMemberCount subquery as an example.
Related
I have a Model associated with two more models by hasMany.
Need a count of both Model's ids
Model.findAndCountAll({
attributes: {
include: [
[sequelize.fn('COUNT', sequelize.col('IncludeModel1.id')), 'includeModel1Count'],
[sequelize.fn('COUNT', sequelize.col('IncludeModel2.id')), 'IncludeModel2Count']
]
},
include: [
{ model: IncludeModel2, attributes: [] },
{
model: IncludeModel1,
attributes: [],
required: true
}
],
subQuery: false,
limit: this.details.limit || 10,
offset: this.details.offset || 0,
group: ['Model.id']
})
Gives Wrong Count
Can you show me the right way?
Thank You
I want to this query in Sequelize:
const results = await WorkflowAssignation.findAndCountAll(
{
limit: limit,
offset: offset,
where:
{
userId: userIds,
status: status
},
include: [
{
model: WorkflowStepAssignation,
include: [
{ model: WorkflowStepAssignationHasUser, include: [ users ]}
]
},
{ model: users }
],
distinct: true,
order: [ [ 'createdAt', 'DESC'], [ { model: WorkflowStepAssignation, as: "steps" }, 'stepNumber', 'ASC' ] ]
});
The problem is that I need to return only WorkflowAssignation if the WorkflowStepAssignationHasUser table contain at least 1 record with the value passed as parameter for userid.
if I used a where in this line { model: WorkflowStepAssignationHasUser, include: [ users ]} it will still return all the WorkflowAssignation with only the steps that has the userId value and that's not what I want.
It is like I want to return all the WorkflowAssignation including all the tables but only if in WorkflowStepAssignation -> WorkflowStepAssignationHasUser has the users in the parameters.
Relations are:
WorkflowAssignation
has Many
WorkflowStepAssignation
has Many
WorkflowStepAssignationHasUser (has a userId column)
add required: true
const results = await WorkflowAssignation.findAndCountAll(
{
limit: limit,
offset: offset,
where:
{
userId: userIds,
status: status
},
include: [
{
model: WorkflowStepAssignation,
include: [
{ model: WorkflowStepAssignationHasUser, include: [ users ]}
]
},
{ model: users }
],
distinct: true,
required: true,
order: [ [ 'createdAt', 'DESC'], [ { model:
WorkflowStepAssignation, as: "steps" }, 'stepNumber', 'ASC' ] ]
});
I am attempting to join two tables defined below in a one-to-many relationship. One Characteristic to many ReviewCharacteristics. Using the following findAll function I am attempting to avg the values in the ReviewCharacteristics table. I have verified the necessary SQL command that should function as expected. Sequelize is including ReviewCharateristic.id in the selected attributes which is causing my grouping to fail.
Is there a way to specify just the avg value and not include the id from the ReviewCharacteristic table in the selected attributes?
exports.Characteristic = db.define('characteristic', {
product_id: {
type: DataTypes.INTEGER,
allowNull: false
},
name: {
type: DataTypes.STRING(7),
allowNull: false
}
}, { underscored: true });
exports.ReviewCharacteristic = db.define('review_characteristic', {
value: {
type: DataTypes.INTEGER,
allowNull: false
}
}, { underscored: true });
exports.Characteristic.hasMany(exports.ReviewCharacteristic, { as: 'rc' });
exports.ReviewCharacteristic.belongsTo(exports.Characteristic);
Characteristic.findAll({
attributes: ['name', 'id'],
where: {
product_id: req.query.product_id
},
group: 'characteristic.id',
include: [{
model: ReviewCharacteristic,
as: 'rc',
attributes: [[Sequelize.fn('AVG', Sequelize.col('rc.value')), 'value']],
required: true
}]
});
I have also tried specifying attributes: ['characteristic.name', 'characteristic.id']
Current:
SELECT
"characteristic"."name",
"characteristic"."id",
"rc"."id" AS "rc.id",
AVG("rc"."value") AS "rc.value"
FROM "characteristic" AS "characteristic"
INNER JOIN "review_characteristic" AS "rc"
ON "characteristic"."id" = "rc"."characteristic_id"
WHERE "characteristic"."product_id" = '18078'
GROUP BY "characteristic"."id";
Expected:
SELECT
"characteristic"."name",
"characteristic"."id",
AVG("rc"."value") AS "rc.value"
FROM "characteristic" AS "characteristic"
INNER JOIN "review_characteristic" AS "rc"
ON "characteristic"."id" = "rc"."characteristic_id"
WHERE "characteristic"."product_id" = '18078'
GROUP BY "characteristic"."id";
If anyone happens to stumble across this question and is dealing with the same issue here is the solution I found.
Characteristic.findAll({
attributes: ['name', 'id', [Sequelize.fn('AVG', Sequelize.col('rc.value')), 'value']],
where: {
product_id: req.query.product_id
},
group: 'characteristic.id',
include: [{
model: ReviewCharacteristic,
as: 'rc',
attributes: [],
required: true
}]
});
The attributes must be specified as an empty array for the joined table in order to stop the addition of the ReviewCharateristic.id attribute in my case.
I'm trying to grab the total number of rows (count) from a nested include in Sequelize. I've followed countless questions on here, but can't seem to get it right.
Models:
Brand
BrandProfile (alias: brand_profile)
BrandPageView (alias brand_page_view)
Relationships:
// Brand
Brand.hasOne(models.BrandProfile, {
foreignKey: 'brand_id',
as: 'brand_profile'
})
// BrandProfile
BrandProfile.belongsTo(models.Brand, {
foreignKey: 'brand_id',
})
BrandProfile.hasMany(models.BrandPageView, {
foreignKey: 'brand_id',
as: 'brand_page_views'
})
// BrandPageView
BrandProfile.belongsTo(models.BrandProfile, {
foreignKey: 'brand_id',
})
Now when I try to normally run my query like so:
const { count, rows } = await Brand.findAndCountAll({
include: [
{
model: BrandProfile,
as: 'brand_profile',
include: [
{
model: BrandPageView,
as: 'brand_page_views',
},
],
},
],
})
It returns the following:
{
id: 1,
created_at: '2020-12-26T20:42:19.930Z',
updated_at: '2020-12-29T20:46:58.918Z',
deleted_at: null,
name: 'Test brand',
slug: 'test-brand',
status: 'disabled',
brand_profile: {
created_at: '2020-12-26T20:42:19.931Z',
about: [ [Object], [Object], [Object], [Object] ],
cleaned_about: null,
subtitle: 'subtitle test',
photo: '1609477287152.jpeg',
photo_config: { scale: '1.00' },
id: 1,
updated_at: '2021-01-01T05:01:27.414Z',
brand_id: 1,
brand_page_views: [
[Object], [Object],
[Object], [Object],
[Object], [Object],
[Object]
]
},
}
As you can see, brand.brand_profile.brand_page_views has a list of all objects. Now I just want to return the count, so I'm using the following query:
const { count, rows } = await Brand.findAndCountAll({
include: [
{
model: BrandProfile,
as: 'brand_profile',
include: {
model: BrandPageView,
as: 'brand_page_views',
attributes: [],
},
},
],
attributes: {
include: [
[
Sequelize.fn('COUNT', Sequelize.col('brand_profile.brand_page_views.brand_id')),
'brand_page_views_count',
],
],
},
group: ['brand.id']
})
I get this error:
'missing FROM-clause entry for table "brand"'
The SQL it outputs is:
SELECT "Brand"."id", "Brand"."created_at", "Brand"."updated_at", "Brand"."deleted_at", "Brand"."name", "Brand"."slug", "Brand"."status", COUNT("brand_profile->brand_page_views"."brand_id") AS "brand_profile.brand_page_views.count", "brand_profile"."created_at" AS "brand_profile.created_at", "brand_profile"."about" AS "brand_profile.about", "brand_profile"."cleaned_about" AS "brand_profile.cleaned_about", "brand_profile"."subtitle" AS "brand_profile.subtitle", "brand_profile"."photo" AS "brand_profile.photo", "brand_profile"."email" AS "brand_profile.email", "brand_profile"."photo_config" AS "brand_profile.photo_config", "brand_profile"."id" AS "brand_profile.id", "brand_profile"."updated_at" AS "brand_profile.updated_at", "brand_profile"."brand_id" AS "brand_profile.brand_id" FROM "brands" AS "Brand" LEFT OUTER JOIN "brand_profile" AS "brand_profile" ON "Br2021-01-05 01:32:26 [sequelize] INFO Executing (default): SELECT "Brand"."id", "Brand"."created_at", "Brand"."updated_at", "Brand"."deleted_at", "Brand"."name", "Brand"."slug", "Brand"."status", COUNT("brand_profile->brand_page_views"."brand_id") AS "brand_profile.brand_page_views.count", "brand_profile"."created_at" AS "brand_profile.created_at", "brand_profile"."about" AS "brand_profile.about", "brand_profile"."cleaned_about" AS "brand_profile.cleaned_about", "brand_profile"."subtitle" AS "brand_profile.subtitle", "brand_profile"."photo" AS "brand_profile.photo", "brand_profile"."email" AS "brand_profile.email", "brand_profile"."photo_config" AS "brand_profile.photo_config", "brand_profile"."id" AS "brand_profile.id", "brand_profile"."updated_at" AS "brand_profile.updated_at", "brand_profile"."brand_id" AS "brand_profile.brand_id" FROM "brands" AS "Brand" LEFT OUTER JOIN "brand_profile" AS "brand_profile" ON "Brand"."id" = "brand_profile"."brand_id" LEFT OUTER JOIN "brand_page_views" AS "brand_profile->braand"."id" = "brand_profile"."brand_id" LEFT OUTER JOIN "brand_page_views" AS "brand_profile->brand_page_views" ON "brand_profile"."id" = "brand_profile->brand_page_views"."brand_id" WHERE "Brand"."id" = 1 GROUP BY "brand"."id";
nd_page_views" ON "brand_profile"."id" = "brand_profile->brand_page_views"."brand_id" WHERE "Brand"."id" = 1 GROUP BY "brand"."id";
I've honestly tried this so many ways, added brand_profile->brand_page_views.brand_id, brand_profile.brand_id to the group, but to no avail.
Sequelize was not designed to support a wide variety of SQL aggregations. So in your case you should use sequelize.literal with a subquery to count child records:
attributes: {
include: [
[Sequelize.literal('(select COUNT(*) from brand_page_views where brand_page_views.brand_id=brand_profile.id)'),
'brand_page_views_count'],
],
},
Don't forget to remove group: ['brand.id']
Consider the following Mongoose schema:
new mongoose.Schema({
attributes: [{
key: { type: String, required: true },
references: [{
value: { type: String, required: true },
reference: { type: mongoose.Schema.Types.ObjectId, required: true }
}]
}
});
A document that follows this schema would look like this:
{
attributes: [
{
key: 'age', references: [{ value: '35', reference: 298387adef... }]
},
{
key: 'name', references: [{
value: 'Joe', reference: 13564afde...,
value: 'Joey', reference: 545675cdab...,
}
...
]
}
I'd like to select attributes according to the following conditions:
- the key is name for example
- the attribute with key name has a least one reference with a value Joe.
Ideally, I'd like to AND-chain many of these conditions. For example, {'name': 'Joe'} and {'age': '35'}.
I can't seem to find a way of doing that Mongoose. I've tried the following Mongoose queries without any good results (it gives either false positives or false negatives):
// First query
query.where('attributes.key', attribute.key);
query.where('attributes.references.value', attribute.value);
// Second
query.and([{ 'attributes.key': attribute.key }, { 'attributes.$.references.value': attribute.value }]);
// Third
query.where('attributes', { 'key': attribute.key, 'references.value': { $in: [attribute.value] }});
So how do I do it?
You can use elemMatch to find docs that contain an attributes element that matches multiple terms:
query.elemMatch(attributes, { key: 'name', 'references.value': 'Joe' })
You can't chain multiple elemMatch calls together though, so if you want to AND multiples of these you'd need to explicitly build up a query object using $and and $elemMatch instead of chaining Query method calls.