Sequelize не возвращает все строки для данного запроса

У меня есть следующие модели секвенирования:

import { DataTypes, Model } from 'sequelize';

class A extends Model{}

A.init {
  name: DataTypes.STRING,
  start_date: DataTypes.DATE,
  end_date: DataTypes.DATE,
  deleted: DataTypes.BOOLEAN
  
}
class B extends Model {}
B.init {
   a_id: DataTypes.Integer,
   text: DataTypes.String,
   created_at: DataTypes.STRING,
   updated_at: DataTypes.DATE,
}
B.belongsTo(A);
A.hasMany(B);

Я пытаюсь выполнить запрос, чтобы получить первые 50 записей A с левым внешним соединением B. По какой-то причине я получаю только 49 записей. Что странно, если я возьму запрос, сгенерированный в свойстве logging, и воспользуюсь таким инструментом, как DBeaver, я получу все 50 строк.

Вот как создается запрос:

const params = {
  limit: 50,
  offset: 0,
  order: [ [ 'id', 'desc']],
  attributes: [
    'id',
    'name',
    'start_date',
    'end_date',
  ],
  subQuery: false,
  where: { deleted: false },
  include: [{model: B}],
  logging: console.info
}

const results = await A.findAll(params);
//length of results is 49

А вот запрос, который генерируется свойством logging:

(Обратите внимание, что я не включил все столбцы в список для удобства чтения)

SELECT * 
FROM "A" LEFT OUTER JOIN B ON "A"."id" = "B"."a_id" 
WHERE "A"."deleted" = false 
ORDER BY "A"."id" DESC 
LIMIT 50 OFFSET 0;

Запрос Sequelize возвращает 49 строк. Запрос, созданный на основе запроса Sequelize, возвращает 50.

Некоторые другие точки данных

  • Если я уберу включение из параметров, я получу все 50 результатов в сиквеле findAll.
  • Если я изменю предел на 25, то функция sqelize findAll вернет 25 результатов.
  • Если я изменю ограничение на 100, то секвенирование findAll вернет 99 строк, но сгенерированный запрос вернет 100.
  • У меня около 1000 строк для таблицы A. Между таблицей A и таблицей B существует связь один-ко-многим. Все строки в таблице A имеют хотя бы одну строку таблицы B. Единственным исключением является то, что в таблице есть ровно одна строка. A, у которого нет строк в таблице B.
  • Я попытался очистить таблицу B, чтобы проверить, возникла ли проблема с объединением, но получил те же результаты, что и при наличии данных в этой таблице.

Обновлять:

  • Вот код, который я использую для распечатки результатов:
const results = await this.A.findAll(findParams);
console.info('Final results: ', results.length);
  • Когда я очистил таблицу B, появились все строки таблицы A.

🤔 А знаете ли вы, что...
Node.js поддерживает платформу Event Loop, что обеспечивает высокую производительность при обработке запросов.


66
1

Ответ:

Решено

По умолчанию Sequelize объединит связанную модель во внутренний массив. Из-за композиции при подсчете длины результата фактически подсчитывается количество различных записей модели A.

Бывший:

SQL-вывод

| id | name | a_id | text |
|  1 |   a1 |    1 |   b1 |
|  1 |   a1 |    1 |   b2 |
|  2 |   a2 |    2 |   b3 |

Это будет составлено в

[
  {
    "id": 1,
    "name": "a1",
    "b" : [
      {
        "text": "b1"
      },
      {
        "text": "b2"
      }
    ]
  },
  {
    "id": 2,
    "name": "a2",
    "b": [
      {
        "text": "b3"
      }
    ]
  }
]

Если вы подсчитаете длину родительского массива, вы увидите 2, а вывод SQL — 3. На самом деле вам нужно посчитать количество элементов во внутренних массивах, которое должно соответствовать счетчику SQL.

Если вы не хотите, чтобы Sequelize компоновал таким образом, вы можете отключить эту композицию,

params = {
  ...
  raw: true,
  nest: true
}