#javascript #sql #node.js #postgresql #sequelize.js
#javascript #sql #node.js #postgresql #sequelize.js
Вопрос:
Моя проблема в двух словах: я хочу использовать операцию И в объединенной таблице. Я думаю, что это очень общий вариант использования в реальной жизни, но я пока не нашел ни одной связанной статьи, блога или проблемы. (Я думаю, это плохо: D)
Позвольте мне описать пример того, что я имею в виду: я хотел бы создать веб-магазин, и у меня есть мобильная и функциональная модели, и между ними существует отношение «многие ко многим». Для этой функции есть фильтр с несколькими вариантами выбора (на моем веб-сайте), и я хочу перечислить те мобильные телефоны, у которых есть выбранные функции. (например.: A, B и C …) Я думаю, что я не могу создать его одним запросом, потому что столбец не может быть A и B одновременно, но я не уверен. Пример:
const mobiles = await models.mobile.findAll({
where: '???',
attributes: ['id', 'name'],
include: [
{
model: models.feature,
where: '???',
attributes: ['id', 'name],
through: {
attributes: [],
},
},
],
});
Меня интересует Sequelize, а также SQL-решение.
Примеры моделей и ожидаемый результат:
const Mobile = sequelize.define('Mobile', {
id: {
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER,
},
name: {
type: DataTypes.STRING
}
}, {});
const Feature = sequelize.define('Feature', {
id: {
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER,
},
name: {
type: DataTypes.STRING
}
}, {});
Mobile.belongsToMany(Feature, { through: 'MobileFeature' });
Feature.belongsToMany(Mobile, { through: 'MobileFeature' });
// Example Data in DB (from mobile context)
const exampleData = [
{
"id": 1,
"name": "Mobile1",
"features": [
{
"id": 1,
"name": "A",
},
{
"id": 2,
"name": "B",
},
{
"id": 3,
"name": "C",
},
],
},
{
"id": 2,
"name": "Mobile2",
"features": [],
},
{
"id": 3,
"name": "Mobile3",
"features": [
{
"id": 1,
"name": "A",
},
]
}
];
// Expected result
// Scenario: I want to list those mobiles which have A and C feature
const result = [
{
"id": 1,
"name": "Mobile1",
"features": [
{
"id": 1,
"name": "A",
},
{
"id": 2,
"name": "B",
},
{
"id": 3,
"name": "C",
},
]
},
];
Комментарии:
1. Можете ли вы предоставить простой пример модели Sequelize для обоих
mobile
иfeature
и их ассоциации, пример данных и ожидаемый результат?2. Я добавил несколько примеров, надеюсь, это поможет.
Ответ №1:
Я думаю, что здесь будет более сложный запрос, чем просто where
.
Можете ли вы предоставить SQL-запрос, который подходит для вашей проблемы? Я думаю, вам нужно будет использовать GROUP BY, COUNT и HAVING (но это только предположение, сделайте по-своему ;))
Если я правильно понимаю вашу проблему: объедините мобильные и функциональные таблицы. Затем используйте where
результат
WHERE: {
name: { [Op.or]: [A,B,C] } // here we pass array of selected feature names to where. It returns mobiles only with this features. But we are looking for mobile with ALL features passed in array)
}
сгруппируйте его по Mobile.name , подсчитайте функции в каждом мобильном телефоне и возьмите этот мобильный телефон, который имеет количество функций = выбранные функции пользователем (так что мобильный со всеми функциями, которые мы ищем).
Конечно, в конечном итоге это будет один оператор sequelize.
ОБНОВЛЕНИЕ: отвечая на ваш вопрос в комментарии к этому ответу:
Сначала вам нужно подсчитать функции. Поэтому мы будем использовать COUNT
и сохранять выходные данные в CountedFeatures
столбце:
attributes: ['id', 'name', [sequelize.fn('COUNT', 'table.fieldToCount'), 'CountedFeatures']],
Затем вам нужно сгруппировать его с помощью group
. Пример использования:
group: ["table.name, table.id"]
И затем вы enter code here
используете having
using предыдущий созданный countedFeatures
столбец:
having: sequelize.where(sequelize.fn('COUNT', 'countedFeatures'), '=', searchedFeaturesArray.length)
Итак, структура в коде будет выглядеть примерно так:
(...).findAll({
attributes: [...],
include : [
(...)
],
group: [...],
having: [...]
})
Также вы можете включить ведение журнала SQL-инструкций в консоль, чтобы посмотреть, что на самом деле происходит после завершения.
Для этого добавьте logging: console.log
атрибут as в findAll
функцию.
Комментарии:
1. Звучит разумно. У меня есть два вопроса: 1. Должен ли я использовать «sequelize literal» в «having»? 2. Как я могу собрать «функции», если я добавлю group by?