合并
通过将作用域数组传递到 .scope
或通过将作用域作为连续参数传递,可以同时应用多个作用域.
// 这两个是等价的
Project.scope('deleted', 'activeUsers').findAll();
Project.scope(['deleted', 'activeUsers']).findAll();
SELECT * FROM projects
INNER JOIN users ON projects.userId = users.id
WHERE projects.deleted = true
AND users.active = true
如果要将其他作用域与默认作用域一起应用,请将键 defaultScope
传递给 .scope
:
Project.scope('defaultScope', 'deleted').findAll();
SELECT * FROM projects WHERE active = true AND deleted = true
当调用多个作用域时,后续作用域的键将覆盖以前的作用域(类似于 Object.assign),除了where
和include
,它们将被合并. 考虑两个作用域:
{
scope1: {
where: {
firstName: 'bob',
age: {
[Op.gt]: 20
}
},
limit: 2
},
scope2: {
where: {
age: {
[Op.gt]: 30
}
},
limit: 10
}
}
调用 .scope('scope1', 'scope2')
将产生以下查询
WHERE firstName = 'bob' AND age > 30 LIMIT 10
注意 scope2
将覆盖 limit
和 age
,而 firstName
被保留. limit
,offset
,order
,paranoid
,lock
和raw
字段被覆盖,而where
被浅层合并(意味着相同的键将被覆盖). include
的合并策略将在后面讨论.
请注意,多个应用作用域的 attributes
键以这样的方式合并,即始终保留 attributes.exclude
. 这允许合并多个作用域,并且永远不会泄漏最终作用域内的敏感字段.
将查找对象直接传递给作用域模型上的findAll
(和类似的查找程序)时,适用相同的合并逻辑:
Project.scope('deleted').findAll({
where: {
firstName: 'john'
}
})
WHERE deleted = true AND firstName = 'john'
这里的 deleted
作用域与 finder 合并. 如果我们要将 where: { firstName: 'john', deleted: false }
传递给 finder,那么 deleted
作用域将被覆盖.
合并 include
Include 是根据包含的模型递归合并的. 这是一个非常强大的合并,在 v5 上添加,并通过示例更好地理解.
考虑四种模型:Foo,Bar,Baz和Qux,具有如下多种关联:
class Foo extends Model {}
class Bar extends Model {}
class Baz extends Model {}
class Qux extends Model {}
Foo.init({ name: Sequelize.STRING }, { sequelize });
Bar.init({ name: Sequelize.STRING }, { sequelize });
Baz.init({ name: Sequelize.STRING }, { sequelize });
Qux.init({ name: Sequelize.STRING }, { sequelize });
Foo.hasMany(Bar, { foreignKey: 'fooId' });
Bar.hasMany(Baz, { foreignKey: 'barId' });
Baz.hasMany(Qux, { foreignKey: 'bazId' });
现在,考虑Foo上定义的以下四个作用域:
{
includeEverything: {
include: {
model: this.Bar,
include: [{
model: this.Baz,
include: this.Qux
}]
}
},
limitedBars: {
include: [{
model: this.Bar,
limit: 2
}]
},
limitedBazs: {
include: [{
model: this.Bar,
include: [{
model: this.Baz,
limit: 2
}]
}]
},
excludeBazName: {
include: [{
model: this.Bar,
include: [{
model: this.Baz,
attributes: {
exclude: ['name']
}
}]
}]
}
}
这四个作用域可以很容易地深度合并,例如通过调用 Foo.scope('includeEverything', 'limitedBars', 'limitedBazs', 'excludeBazName').findAll()
,这完全等同于调用以下内容:
Foo.findAll({
include: {
model: this.Bar,
limit: 2,
include: [{
model: this.Baz,
limit: 2,
attributes: {
exclude: ['name']
},
include: this.Qux
}]
}
});
观察四个作用域如何合并为一个. 根据所包含的模型合并作用域的include. 如果一个作用域包括模型A而另一个作用域包括模型B,则合并结果将包括模型A和B.另一方面,如果两个作用域包括相同的模型A,但具有不同的参数(例如嵌套include或其他属性) ,这些将以递归方式合并,如上所示.
无论应用于作用域的顺序如何,上面说明的合并都以完全相同的方式工作. 如果某个参数由两个不同的作用域设置,那么只会该顺序产生差异 - 这不是上述示例的情况,因为每个作用域都做了不同的事情.
这种合并策略的工作方式与传递给.findAll
,.findOne
等的参数完全相同.