My problem in nutshell: I want to use the AND operation in a joined table. I think it is a very general use-case in the real life, but I didn't find any related article, blog, or issue yet. (My bad I think:D)
Let me describe an example of what I mean: I would like to create a webshop and I have a Mobile and a Feature model and there is many-to-many relation between them. There is a multi-select filter for the feature (on my website) and I want to list those mobiles which have selected features. (eg.: A and B and C...) I think I cannot create it one query because a column cannot be A and B at the same time, but I'm not sure. Example:
const mobiles = await models.mobile.findAll({
where: '???',
attributes: ['id', 'name'],
include: [
{
model: models.feature,
where: '???',
attributes: ['id', 'name],
through: {
attributes: [],
},
},
],
});
I'm interested in the Sequelize and also the SQL solution too.
Example models and expected result:
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",
},
]
},
];
I think here will be more complex query than just where
.
Can you provide SQL query which suits to your problem? I guess you will need to use GROUP BY, COUNT and HAVING (but this is only ma assumption, make it your way;) )
If I understand your problem right: Join Mobile and Feature tables. Then use where
on result
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)
}
group it by Mobile.name, count Features in every mobile and take this mobile which having features number = selected feateures by user (so mobile with all features we are looking for).
Of course finally it will be one sequelize statement.
UPDATE : answering your question in comment to this answer:
First you need to count features. So we will use COUNT
and store output in CountedFeatures
column:
attributes: ['id', 'name', [sequelize.fn('COUNT', 'table.fieldToCount'), 'CountedFeatures']],
Then you need to group it using group
. Example of use:
group: ["table.name, table.id"]
And then you enter code here
use having
using previous created countedFeatures
column:
having: sequelize.where(sequelize.fn('COUNT', 'countedFeatures'), '=', searchedFeaturesArray.length)
So structure in code it will look something like this:
(...).findAll({
attributes: [...],
include : [
(...)
],
group: [...],
having: [...]
})
Also you can turn on SQL statement logging to console to see what really happens uderneath. To do this add logging: console.log
as attribute in findAll
function.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.