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.

Я обновил свой экземпляр postgres, чтобы регистрировать все запросы, и появившийся запрос был таким же, как тот, который показывал мне console.info. Этот запрос возвращал все 50 строк.

lordoku 27.06.2024 00:35

Как вы измеряете размер результата, всего console.info(results.length)? Вы делаете это сразу после оператора findAll или позже, когда какой-то другой код уже мог мутировать results? Единственное объяснение, которое я могу придумать, это неосторожный results.pop() звонок куда-то.

Bergi 27.06.2024 00:50

Я обновлю свой вопрос, включив в него ответ на ваш вопрос, @Bergi

lordoku 27.06.2024 01:03

Вы можете просто указать separate: true в опции include, чтобы добиться правильного результата. Для лучшего объяснения смотрите мой ответ здесь: stackoverflow.com/a/61763084/1376618

Anatoly 27.06.2024 18:51

Кажется, это исправило ситуацию. Почему по умолчанию не включаются все связанные записи? Какие записи включаются, а какие исключаются? Почему соединение не возвращает все правильные записи? Меня беспокоит снижение производительности при использовании отдельного файла. Кроме того, почему сгенерированный запрос возвращает все правильные записи, а код продолжения — нет? Вот объяснение того, что делает/означает отдельный: stackoverflow.com/questions/37964763/…

lordoku 27.06.2024 19:35
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
66
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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
}

Другие вопросы по теме