0

Sequelize: Поиск по ассоциации

13

Как использовать Sequelize для поиска всех людей, у которых столбец в связи соответствует определенному условию?

Пример: нужно найти все Книги, авторы которых имеют фамилию 'Hitchcock'. Схема книги содержит отношение hasOne с таблицей Авторов.

Редактирование: Я понимаю, как это можно сделать с помощью сырого SQL-запроса, но ищу другой подход.

3 ответ(ов)

0

Вот рабочий пример того, как использовать Sequelize для получения всех Books у Author с определенной фамилией. Код выглядит более сложным, чем на самом деле, поскольку я определяю модели, создаю связи между ними, синхронизирую с базой данных (чтобы создать их таблицы), а затем создаю тестовые данные в этих новых таблицах. Ищите findAll в середине кода, чтобы увидеть конкретно то, что вам нужно.

module.exports = function(sequelize, DataTypes) {

    var Author = sequelize.define('Author', {

        id: {
            type: DataTypes.INTEGER,
            allowNull: false,
            autoIncrement: true,
            primaryKey: true
        },
        firstName: {
            type: DataTypes.STRING
        },
        lastName: {
            type: DataTypes.STRING
        }

    });

    var Book = sequelize.define('Book', {

        id: {
            type: DataTypes.INTEGER,
            allowNull: false,
            autoIncrement: true,
            primaryKey: true
        },
        title: {
            type: DataTypes.STRING
        }

    });

    var firstAuthor;
    var secondAuthor;

    Author.hasMany(Book);
    Book.belongsTo(Author);

    Author.sync({ force: true })
        .then(function() {
            return Book.sync({ force: true });
        })
        .then(function() {
            return Author.create({firstName: 'Test', lastName: 'Testerson'});
        })
        .then(function(author1) {
            firstAuthor = author1;
            return Author.create({firstName: 'The Invisible', lastName: 'Hand'});
        })
        .then(function(author2) {
            secondAuthor = author2;
            return Book.create({AuthorId: firstAuthor.id, title: 'A simple book'});
        })
        .then(function() {
            return Book.create({AuthorId: firstAuthor.id, title: 'Another book'});
        })
        .then(function() {
            return Book.create({AuthorId: secondAuthor.id, title: 'Some other book'});
        })
        .then(function() {
            // Это именно то, что вам нужно.
            return Book.findAll({
                where: {
                    'Authors.lastName': 'Testerson'
                },
                include: [
                    { model: Author, as: Author.tableName }
                ]
            });
        })
        .then(function(books) { 
            console.log('Найдено ' + books.length + ' книг у Test Testerson');
        });
}

Обратите внимание на то, что в запросе findAll используется where для фильтрации книг по фамилии автора. Также вспомогательная модель Author включается в выборку с помощью include, чтобы получить всю необходимую информацию о авторах.

0

В последней версии Sequelize (5.9.0) метод, предложенный @c.hill, больше не работает. Теперь вам нужно использовать следующий код:

return Book.findAll({
    where: {
        '$Authors.lastName$': 'Testerson'
    },
    include: [
        {model: Author, as: Author.tableName}
    ]
});

Обратите внимание, что в данном случае важно использовать синтаксис с $ для доступа к полям связанных моделей в условии where, а также убедитесь, что название ассоциации указано правильно. Если у вас возникнут дополнительные вопросы по реализации, не стесняйтесь спрашивать!

0

Для документации!

Проверьте раздел об жадной выборке (eager loading) по следующей ссылке:

https://sequelize.org/master/manual/eager-loading.html

Что касается вышеуказанных ответов, нужную информацию можно найти в документации под заголовком

Сложные условия WHERE на верхнем уровне

Из документации:

Чтобы получить верхнеуровневые условия WHERE, которые касаются вложенных колонок, Sequelize предоставляет способ ссылаться на вложенные колонки с помощью синтаксиса: '\(nested.column\)'.

Это может быть, например, использовано для того, чтобы переместить условия WHERE из включенной модели из условия ON в верхнеуровневое условие WHERE.

User.findAll({
  where: {
    '$Instruments.size$': { [Op.ne]: 'small' }
  },
  include: [{
    model: Tool,
    as: 'Instruments'
  }]
});

Сгенерированный SQL:

SELECT
  `user`.`id`,
  `user`.`name`,
  `Instruments`.`id` AS `Instruments.id`,
  `Instruments`.`name` AS `Instruments.name`,
  `Instruments`.`size` AS `Instruments.size`,
  `Instruments`.`userId` AS `Instruments.userId`
FROM `users` AS `user`
LEFT OUTER JOIN `tools` AS `Instruments` ON
  `user`.`id` = `Instruments`.`userId`
WHERE `Instruments`.`size` != 'small';

Для лучшего понимания всех различий между внутренними условиями where (используемыми внутри include) с опцией required и без нее, а также верхнеуровневым условием where с использованием синтаксиса \(nested.column\), ниже приведены четыре примера:

// Внутреннее условие where, с `required: true` по умолчанию
await User.findAll({
  include: {
    model: Tool,
    as: 'Instruments',
    where: {
      size: { [Op.ne]: 'small' }
    }
  }
});

// Внутреннее условие where, `required: false`
await User.findAll({
  include: {
    model: Tool,
    as: 'Instruments',
    where: {
      size: { [Op.ne]: 'small' }
    },
    required: false
  }
});

// Верхнеуровневое условие where, с `required: false` по умолчанию
await User.findAll({
  where: {
    '$Instruments.size$': { [Op.ne]: 'small' }
  },
  include: {
    model: Tool,
    as: 'Instruments'
  }
});

// Верхнеуровневое условие where, `required: true`
await User.findAll({
  where: {
    '$Instruments.size$': { [Op.ne]: 'small' }
  },
  include: {
    model: Tool,
    as: 'Instruments',
    required: true
  }
});

Сгенерированные SQL-запросы в порядке:

-- Внутреннее условие where, с `required: true`
SELECT [...] FROM `users` AS `user`
INNER JOIN `tools` AS `Instruments` ON
  `user`.`id` = `Instruments`.`userId`
  AND `Instruments`.`size` != 'small';

-- Внутреннее условие where, `required: false`
SELECT [...] FROM `users` AS `user`
LEFT OUTER JOIN `tools` AS `Instruments` ON
  `user`.`id` = `Instruments`.`userId`
  AND `Instruments`.`size` != 'small';

-- Верхнеуровневое условие where, с `required: false`
SELECT [...] FROM `users` AS `user`
LEFT OUTER JOIN `tools` AS `Instruments` ON
  `user`.`id` = `Instruments`.`userId`
WHERE `Instruments`.`size` != 'small';

-- Верхнеуровневое условие where, `required: true`
SELECT [...] FROM `users` AS `user`
INNER JOIN `tools` AS `Instruments` ON
  `user`.`id` = `Instruments`.`userId`
WHERE `Instruments`.`size` != 'small';

Это дает нам хорошее представление о том, как выполняются соединения (join)!

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь