sequelize: `limit` with `subQuery: false` return wrong result

What are you doing?

Let’s say I have Transaction model which have many-to-many relation with Good model. And also belongs to User model. Here’s my model and relation definition.

module.exports = (sequelize, DataTypes) => {
  const Transaction = sequelize.define('Transaction', {
    id: {
      type: DataTypes.UUID,
      primaryKey: true,
      defaultValue: DataTypes.UUIDV4,
      allowNull: false,
      autoIncrement: false,
    },
    userId: {
      type: DataTypes.UUID,
      allowNull: false,
      foreignKey: true,
      references: {
        model: 'users',
        key: 'id',
      },
    },
    status: DataTypes.ENUM('verified', 'waiting', 'empty', 'rejected'),
    channel: {
      type: DataTypes.INTEGER,
      allowNull: false,
    },
  }, {});

  Transaction.associate = (models) => {
    Transaction.belongsTo(models.User, { as: 'user', foreignKey: 'userId' });
  };

  return Transaction;
};
module.exports = (sequelize, DataTypes) => {
  const Good = sequelize.define('Good', {
    id: {
      type: DataTypes.UUID,
      primaryKey: true,
      defaultValue: DataTypes.UUIDV4,
      allowNull: false,
      autoIncrement: false,
    },
    rphAset: {
      type: DataTypes.BIGINT,
      allowNull: false,
      defaultValue: 0,
    },
    urUpb: {
      type: DataTypes.STRING,
      allowNull: false,
    },
  }, {});

  return Good;
};
db.Good.belongsToMany(db.Transaction, { as: 'transactions', through: db.TransactionGood, foreignKey: 'goodId' });
db.Transaction.belongsToMany(db.Good, { as: 'goods', through: db.TransactionGood, foreignKey: 'transactionId' });

I already seed my database with data so user with id 30e1c140-d4d0-4edb-980a-3d7b9a47a958 has 7 transaction. I want to get transaction for that user with all goods in it. Here’s my code.

const x = await models.Transaction.findAll({
    subQuery: false,
    distinct: true,
    where: {
      userId: '30e1c140-d4d0-4edb-980a-3d7b9a47a958',
    },
    include: [
      {
        model: models.User,
        as: 'user',
        attributes: ['id','name','createdAt','updatedAt'],
      },
      {
        model: models.Good,
        as: 'goods',
      },
    ],
    order: [['createdAt','ASC',]],
    limit: 10,
  });

What do you expect to happen?

It will output array with 7 transcations data (all records in database).

What is actually happening?

It returns array with only 3 data. Here’s generated SQL

SELECT `Transaction`.`id`,
       `Transaction`.`userId`,
       `Transaction`.`status`,
       `Transaction`.`channel`,
       `Transaction`.`createdAt`,
       `Transaction`.`updatedAt`,
       `user`.`id` AS `user.id`,
       `user`.`name` AS `user.name`,
       `user`.`createdAt` AS `user.createdAt`,
       `user`.`updatedAt` AS `user.updatedAt`,
       `goods`.`id` AS `goods.id`,
       `goods`.`rphAset` AS `goods.rphAset`,
       `goods`.`urUpb` AS `goods.urUpb`,
       `goods`.`createdAt` AS `goods.createdAt`,
       `goods`.`updatedAt` AS `goods.updatedAt`,
       `goods->TransactionGood`.`id` AS `goods.TransactionGood.id`,
       `goods->TransactionGood`.`createdAt` AS `goods.TransactionGood.createdAt`,
       `goods->TransactionGood`.`updatedAt` AS `goods.TransactionGood.updatedAt`,
       `goods->TransactionGood`.`goodId` AS `goods.TransactionGood.goodId`,
       `goods->TransactionGood`.`transactionId` AS `goods.TransactionGood.transactionId`
FROM `Transactions` AS `Transaction`
LEFT OUTER JOIN `Users` AS `user`ON `Transaction`.`userId` = `user`.`id`
LEFT OUTER JOIN (`TransactionGoods` AS `goods->TransactionGood`
                 INNER JOIN`Goods` AS `goods` ON `goods`.`id` = `goods->TransactionGood`.`goodId`) ON `Transaction`.`id` = `goods->TransactionGood`.`transactionId`
WHERE `Transaction`.`userId` = '30e1c140-d4d0-4edb-980a-3d7b9a47a958'
ORDER BY `Transaction`.`createdAt` ASC
LIMIT 10;

But when I remove subQuery: false option it will return 7 data. Here’s generated sql without subQuery: false option.

SELECT `Transaction`.*,
       `user`.`id` AS `user.id`,
       `user`.`name` AS `user.name`,
       `user`.`createdAt` AS `user.createdAt`,
       `user`.`updatedAt` AS `user.updatedAt`,
       `goods`.`id` AS `goods.id`,
       `goods`.`rphAset` AS `goods.rphAset`,
       `goods`.`urUpb` AS `goods.urUpb`,
       `goods`.`createdAt` AS `goods.createdAt`,
       `goods`.`updatedAt` AS `goods.updatedAt`,
       `goods->TransactionGood`.`id` AS `goods.TransactionGood.id`,
       `goods->TransactionGood`.`createdAt` AS `goods.TransactionGood.createdAt`,
       `goods->TransactionGood`.`updatedAt` AS `goods.TransactionGood.updatedAt`,
       `goods->TransactionGood`.`goodId` AS `goods.TransactionGood.goodId`,
       `goods->TransactionGood`.`transactionId` AS `goods.TransactionGood.transactionId`
FROM
  (SELECT `Transaction`.`id`,
          `Transaction`.`userId`,
          `Transaction`.`status`,
          `Transaction`.`channel`,
          `Transaction`.`createdAt`,
          `Transaction`.`updatedAt`
   FROM `Transactions` AS `Transaction`
   WHERE `Transaction`.`userId` = '30e1c140-d4d0-4edb-980a-3d7b9a47a958'
   ORDER BY `Transaction`.`createdAt` ASC
   LIMIT 10) AS `Transaction`
LEFT OUTER JOIN `Users` AS `user` ON `Transaction`.`userId` = `user`.`id`
LEFT OUTER JOIN (`TransactionGoods` AS `goods->TransactionGood`
                 INNER JOIN `Goods` AS `goods` ON `goods`.`id` = `goods->TransactionGood`.`goodId`) ON `Transaction`.`id` = `goods->TransactionGood`.`transactionId`
ORDER BY `Transaction`.`createdAt` ASC;

Dialect: mysql Database version: 5.7.18 Sequelize version: 4.38.0 Tested with latest release: Yes

Note : Your issue may be ignored OR closed by maintainers if it’s not tested against latest version OR does not follow issue template.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 3
  • Comments: 26 (7 by maintainers)

Most upvoted comments

@papb FYI: In my case the issue takes place, when I include models with @ HasMany relations. I solved my issue by setting “separate” flag to true

include: [
    {
        model: Offer,
        as: "offers",
        required: false,
        separate: true
    },
    {
        model: DealFund,
        as: "fund",
        include: [
            {
                model: DealFundCharge,
                as: "charges",
                required: false,
                separate: true
            }
        ]
    }
]

Alex

Has there been any progress whatsoever? This is a big deal.

I’ll close this issue as I’ve now documented that limit needs subQuery to be true to work properly

Issues related to $nested.attribute.syntax$ being broken with subQuery: true will be sorted out in this thread

@fkursun Could you open an issue (if you don’t already have one) with what your query looks like, what the generated SQL is, and what you’d expect it to be?

Related PR to clarify how limit works: https://github.com/sequelize/sequelize/pull/13985

@chetanmenge @eldadgiladi @Afinetri No solution and workaround for this, the only option is using bare SQL with knex or bookshelf.