Сиквелировать – где с графом

#javascript #node.js #sequelize.js

Вопрос:

У меня есть три модели, которые расширяются Sequelize.Model и генерируют миграции. Ассоциации выглядят так:

Фу

 Foo.belongsToMany(Bar, {
  as: 'bars',
  through: 'FooBar',
  foreignKey: 'foo_id',
});
 

Бар

 Bar.belongsToMany(Foo, {
  as: 'bars',
  through: 'FooBar',
  foreignKey: 'bar_id',
});
 

Буфет

 FooBar.belongsTo(Foo, {
  as: 'foo',
  foreignKey: 'foo_id',
});
FooBar.belongsTo(Bar, {
  as: 'bar',
  foreignKey: 'bar_id',
});
 

Я пытаюсь запросить Фу вот так:

 const foos = await Foo.findAll({
  include: [{
    model: Bar,
    as: 'bars',
  }],
});
 

Код работает так, как ожидалось, и я получаю массив bars для каждого из моих foo .

Как я могу теперь запрашивать foos, bars количество которых превышает, например, 2?

Ответ №1:

В sequelize нет прямого способа сделать это.
Вы можете сделать это двумя способами:

  • Первый способ: (2 запроса)
    • Найдите все идентификаторы foo, которые имеют 2 строки в 1 запросе (возможно, необработанный запрос)
    • Добавьте эти идентификаторы foo в качестве фильтра в поле «Где вы найдете».
  • Второй способ: (1 запрос)
    • Создайте последовательный литерал подзапроса, который возвращает идентификаторы foo, содержащие более 2 строк, и добавьте этот литерал в where: { id: <subquery literal> }

Показ второго способа:
литерал подзапроса, например:

 sequelize.literal(`(
SELECT 
  id 
FROM foo 
LEFT JOIN bar ON bar.foo_id = foo.id 
WHERE COUNT(bar.id) > 2 
GROUP BY foo.id
)`)
 

Окончательный вывод:

 const foos = await Foo.findAll({
  where: {
    id: sequelize.literal(`...`),
  },
  include: [{
    model: Bar,
    as: 'bars',
  }],
});