Question

I am trying to get a distinct count of a particular column using sequelize. My initial attempt is using the 'count' method of my model, however it doesn't look like this is possible.

The DISTINCT feature is needed because I am joining other tables and filtering the rows of the parent based on the related tables.

here's the query I would like:

SELECT COUNT(DISTINCT Product.id) as `count` 
FROM `Product` 
LEFT OUTER JOIN `Vendor` AS `vendor` ON `vendor`.`id` = `Product`.`vendorId` 
WHERE (`vendor`.`isEnabled`=true );

using the following query against my Product model:

Product.count({
        include: [{model: models.Vendor, as: 'vendor'}],
        where: [{ 'vendor.isEnabled' : true }]
    })

Generates the following query:

SELECT COUNT(*) as `count` 
FROM `Product` 
LEFT OUTER JOIN `Vendor` AS `vendor` ON `vendor`.`id` = `Product`.`vendorId` 
WHERE (`vendor`.`isEnabled`=true );
Was it helpful?

Solution 3

Looks like this is now supported in Sequelize versions 1.7.0+.

the count and findAndCountAll methods of a model will give you 'real' or 'distinct' count of your parent model.

OTHER TIPS

UPDATE: New version

There are now separate distinct and col options. The docs for distinct state:

Apply COUNT(DISTINCT(col)) on primary key or on options.col.

You want something along the lines of:

MyModel.count({
  include: ...,
  where: ...,
  distinct: true,
  col: 'Product.id'
})
.then(function(count) {
    // count is an integer
});

Original Post

(As mentioned in the comments, things have changed since my original post, so you probably want to ignore this part.)

After looking at Model.count method in lib/model.js, and tracing some code, I found that when using Model.count, you can just add any kind of aggregate function arguments supported by MYSQL to your options object. The following code will give you the amount of different values in MyModel's someColumn:

MyModel.count({distinct: 'someColumn', where: {...}})
.then(function(count) {
    // count is an integer
});

That code effectively generates a query of this kind: SELECT COUNT(args) FROM MyModel WHERE ..., where args are all properties in the options object that are not reserved (such as DISTINCT, LIMIT and so on).

The Sequelize documentation on count links to a count method that doesn't let you specify which column to get the count of distinct values:

Model.prototype.count = function(options) {
  options = Utils._.clone(options || {});
  conformOptions(options, this);
  Model.$injectScope(this.$scope, options);
  var col = '*';
  if (options.include) {
    col = this.name + '.' + this.primaryKeyField;
    expandIncludeAll.call(this, options);
    validateIncludedElements.call(this, options);
  }
  Utils.mapOptionFieldNames(options, this);
  options.plain = options.group ? false : true;
  options.dataType = new DataTypes.INTEGER();
  options.includeIgnoreAttributes = false;
  options.limit = null;
  options.offset = null;
  options.order = null;
  return this.aggregate(col, 'count', options);
};

Basically SELECT COUNT(DISTINCT(*)) or SELECT COUNT(DISTINCT(primaryKey)) if you've got a primary key defined.

To do the Sequelize equivalent of SELECT category, COUNT(DISTINCT(product)) as 'countOfProducts' GROUP BY category, you'd do:

model.findAll({
  attributes: [
    'category',
    [Sequelize.literal('COUNT(DISTINCT(product))'), 'countOfProducts']
  ],
  group: 'category'
})

I was searching for SELECT COUNT(0) query for sequelize, below is the answer for that.

    let existingUsers = await Users.count({
        where: whereClouser,
        attributes: [[sequelize.fn('COUNT', 0), 'count']]
    });

This helped me to get distinct count from another table rows,

dataModel.findAll({
    attributes: { 
        include: [[Sequelize.literal("COUNT(DISTINCT(history.data_id))"), "historyModelCount"]] 
    },
    include: [{
        model: historyModel, attributes: []
    }],
    group: ['data.id']
});

Ref 1, Ref 2.

With respect to your question in order to get the distinct counts of products based on the id of product

you just need to pass the key 'distinct' with value 'id' to your count object , Here is the example

To generate this sql query as you asked

SELECT COUNT(DISTINCT(`Product`.`id`)) as `count` 
FROM `Product` 
LEFT OUTER JOIN `Vendor` AS `vendor` ON `vendor`.`id` = `Product`.`vendorId` 
WHERE (`vendor`.`isEnabled`=true );

Add 'distinct' key in your Sequelize query

Product.count({
        include: [{model: models.Vendor, as: 'vendor'}],
        where: [{ 'vendor.isEnabled' : true }],
        distinct: 'id' // since count is applied on Product model and distinct is directly passed to its object so Product.id will be selected
    });

This way of using 'distinct' key to filter out distinct counts or rows , I tested in Sequelize Version 6.

Hope this will help you or somebody else!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top