javascript - Sequelize:在子项中使用“where”包含覆盖父项的“where”标准。涉及复合主键
问题描述
所以,
我有两张表,关系为 1:M。它们有两个共同的主键:tenant 和 user_id。
我已经定义了模型关系,顺便说一句,我不确定我是否正确,因为我仍然不确定如何在 Sequelize 上处理复合主键。这适用于我的许多其他查询,我认为它会影响问题。
// Sequelize model set-up:
const user = serviceLayerDB.define('user',
{ // Database columns:
tenant: {
type: Sequelize.STRING(45),
primaryKey: true
},
user_id: {
type: Sequelize.STRING(24),
primaryKey: true
},
status: {
type: Sequelize.STRING(11)
}
});
const user_component = serviceLayerDB.define('user_component',
{ // Database columns:
tenant: {
type: Sequelize.STRING(45),
primaryKey: true
},
user_id: {
type: Sequelize.STRING(24),
primaryKey: true
},
component_id: {
type: Sequelize.STRING(24),
primaryKey: true
},
active: {
type: Sequelize.BOOLEAN
}
});
// Sequelize relationship set-up:
user.hasMany(user_component, { foreignKey: 'user_id' });
user.hasMany(user_component, { foreignKey: 'tenant' });
但是当我有以下查询时,问题就来了:
// Retrieving user and related components.
function getSubscriptions() {
let options = {
where: {
tenant: 'company_A',
user_id: '1001'
},
include: [{ // Adding components, filtered by "active" value:
model: user_component,
where: {
active: 1
},
required: false
}]
};
user.findAll(options)
.then(function(data) {
if (data.length === 0) { // If no data found:
console.log('No data found');
return;
}
// Curate Sequelize result:
let curatedData = data.map(function(userInstance) { return userInstance.get({ plain: true}) }); // Workaround to be able to perform .get().
console.log(JSON.stringify(curatedData, null, 2));
})
.catch(function(error) {
console.log('critical', 'Failed to find data in database. Error: ' + error);
})
}
// Execute:
getSubscriptions();
我想要的是找到用户及其组件,但只有那些将活动值设置为 1 的组件。它不起作用:结果是在同一个“租户”下,每个组件的活动值都设置为 1,孩子include 忽略了我们在 parent 中指定的“user_id”。
我认为这与我的复合主键有关吗?如何以最优雅的方式解决这个问题?
解决方案
当您将一个模型与另一个模型关联不止一次时,您必须使用别名。例如:
user.hasMany(user_component, { foreignKey: 'user_id', as: 'UserComponents' });
user.hasMany(user_component, { foreignKey: 'tenant', as: 'TenantComponents' });
之后,您应该决定您希望执行包含操作的确切关联:user_id字段的关联
let options = {
where: {
tenant: 'company_A',
user_id: '1001'
},
include: [{ // Adding components, filtered by "active" value:
model: user_component,
as: 'UserComponents'
where: {
active: 1
},
required: false
}]
};
租户领域的协会
let options = {
where: {
tenant: 'company_A',
user_id: '1001'
},
include: [{ // Adding components, filtered by "active" value:
model: user_component,
as: 'TenantComponents'
where: {
active: 1
},
required: false
}]
};
如果您希望两个子集合都具有active: 1条件,您可以这样做:
let options = {
where: {
tenant: 'company_A',
user_id: '1001'
},
include: [{ // Adding components, filtered by "active" value:
model: user_component,
as: 'UserComponents'
where: {
active: 1
},
required: false,
separate: true
}, { // Adding components, filtered by "active" value:
model: user_component,
as: 'TenantComponents'
where: {
active: 1
},
required: false,
separate: true
}]
};
请注意separate: true选项:这个选项告诉sequielize 对childs 做单独的查询。如果您希望获得的不是所有用户,而是那些仅具有活动组件的用户(哪些:通过 user_id 或租户字段?)您应该在 include 中设置 required: true 。但在这种情况下,不要同时包含与 required: true 的关联。这会导致结果 SQL 查询中的记录数量增加,并消耗更多的内存。
推荐阅读
- sql - 检查表中的所有行是否在几列中具有某些值
- javascript - 如何在 NodeJS 的 LEFT JOIN 上将 SQL 查询的结果放入自己的对象中?
- powershell - 如何在 Server 2016 上使用 Powershell 远程重启服务
- c# - 如何在VS2019中为C#设置环境变量
- javascript - 使用 Array.map() 渲染动态数组,但仅适用于选定的值
- c++ - 有没有办法为类中的所有成员可选地使用`std::optional`
- google-chrome - 下载铬失败
- discord.js - 我无法将已在语音通道中的用户移动到另一个语音通道
- ios - LazyVGrid 中的 NavigationLink 循环返回所有条目,SwiftUI
- python-3.x - 为什么导入的值不可调用