Scopes作用域
Scoping allows you to define commonly used queries that you can easily use later. Scopes can include all the same attributes as regular finders, where
, include
, limit
etc.
Scoping允许你去定义普遍使用的查询,这样你之后就能够简单使用。Scopes能够像一般的查询器一样包含 where
, include
, limit
等
Definition
Scopes are defined in the model definition and can be finder objects, or functions returning finder objects - except for the default scope, which can only be an object:
Scopes可以在模型定义中进行定义,也可以是查找器对象或返回查找器对象的函数-除了默认的scope,她才能只是一个对象
const Project = sequelize.define('project', { // Attributes }, { defaultScope: { where: { active: true } }, scopes: { deleted: { where: { deleted: true } }, activeUsers: { include: [ { model: User, where: { active: true }} ] }, random: function () { return { where: { someNumber: Math.random() } } }, accessLevel: function (value) { return { where: { accessLevel: { [Op.gte]: value } } } } } });
You can also add scopes after a model has been defined by calling addScope
. This is especially useful for scopes with includes, where the model in the include might not be defined at the time the other model is being defined.
你可以通过调用addScope
在模型定义后添加scopes。这对带有includes的scopes十分有用,因为在其他模型被定义时include中的模型可能还没有定义
The default scope is always applied. This means, that with the model definition above, Project.findAll()
will create the following query:
缺省scope总是被提供。这意味着有着上面的模型定义,Project.findAll()
将创建出下面的查询:
SELECT * FROM projects WHERE active = true
The default scope can be removed by calling .unscoped()
, .scope(null)
, or by invoking another scope:
缺省scope可以通过调用 .unscoped()
, .scope(null)
函数或调用另一个scope来移除
Project.scope('deleted').findAll(); // Removes the default scope SELECT * FROM projects WHERE deleted = true
It is also possible to include scoped models in a scope definition. This allows you to avoid duplicating include
, attributes
or where
definitions. Using the above example, and invoking the active
scope on the included User model (rather than specifying the condition directly in that include object):
在scope定义中包含scoped模型也是可能的。这要求你避免重复 include
, attributes
或where定义。使用上面的例子并在包含的User模型中调用
active scope(而不是直接在包含对象中指明条件)
activeUsers: { include: [ { model: User.scope('active')} ] }
Usage
Scopes are applied by calling .scope
on the model definition, passing the name of one or more scopes. .scope
returns a fully functional model instance with all the regular methods: .findAll
, .update
, .count
, .destroy
etc. You can save this model instance and reuse it later:
Scopes通过在模型定义中调用.scope来应用,传递一个或多个scopes的名字。
.scope
将返回一个带着传统方法 .findAll
, .update
, .count
, .destroy
等的完整的函数模型实例。你可以保存这个模型实例并在之后重新使用它
const DeletedProjects = Project.scope('deleted'); DeletedProjects.findAll(); // some time passes // let's look for deleted projects again! DeletedProjects.findAll();
Scopes apply to .find
, .findAll
, .count
, .update
, .increment
and .destroy
.
Scopes供应 .find
, .findAll
, .count
, .update
, .increment
和 .destroy方法
Scopes which are functions can be invoked in two ways. If the scope does not take any arguments it can be invoked as normally. If the scope takes arguments, pass an object:
Scopes函数可以以两种方式被调用。如果scope不带任何参数,他将普通地调用。如果带参数,将传递对象:
Project.scope('random', { method: ['accessLevel', 19]}).findAll(); SELECT * FROM projects WHERE someNumber = 42 AND accessLevel >= 19
Merging
Several scopes can be applied simultaneously by passing an array of scopes to .scope
, or by passing the scopes as consecutive arguments.
几个scopes可以同时通过传递scopes数组给 .scope
来被应用,或者通过传递scopes作为连续的参数
// These two are equivalent Project.scope('deleted', 'activeUsers').findAll(); Project.scope(['deleted', 'activeUsers']).findAll(); SELECT * FROM projects INNER JOIN users ON projects.userId = users.id AND users.active = true
If you want to apply another scope alongside the default scope, pass the key defaultScope
to .scope
:
如果你想要跟着缺省scope来应用其他scope,传递键defaultScope
给.scope
:
Project.scope('defaultScope', 'deleted').findAll(); SELECT * FROM projects WHERE active = true AND deleted = true
When invoking several scopes, keys from subsequent scopes will overwrite previous ones (similar to _.assign). Consider two scopes:
当调用几个scopes时,来自子序列scopes的键将复写以前的键值
{ scope1: { where: { firstName: 'bob', age: { [Op.gt]: 20 } }, limit: 2 }, scope2: { where: { age: { [Op.gt]: 30 } }, limit: 10 } }
Calling .scope('scope1', 'scope2')
will yield the following query
调用 .scope('scope1', 'scope2')
产生下面的查询:
WHERE firstName = 'bob' AND age > 30 LIMIT 10
Note how limit
and age
are overwritten by scope2
, while firstName
is preserved. limit
, offset
, order
, paranoid
, lock
and raw
are overwritten, while where
and include
are shallowly merged. This means that identical keys in the where objects, and subsequent includes of the same model will both overwrite each other.
注明怎么通过scope2复写
limit
和age,当
firstName
保存时。
,当
where
和include被浅合并时
limit
, offset
, order
, paranoid
, lock
and raw
都被复写。这意味着在where对象中有着相同的键,并且当自序列包含相同的模型时将互相复写
The same merge logic applies when passing a find object directly to findAll on a scoped model:
当在scoped模型中直接传递一个find对象给findAll时,同样的合并逻辑使用
Project.scope('deleted').findAll({ where: { firstName: 'john' } }) WHERE deleted = true AND firstName = 'john'
Here the deleted
scope is merged with the finder. If we were to pass where: { firstName: 'john', deleted: false }
to the finder, the deleted
scope would be overwritten.
这里deleted scope将与查找器合并。如果我们打算传递
where: { firstName: 'john', deleted: false }
给查找器,deleted
scope将被复写
Associations
Sequelize has two different but related scope concepts in relation to associations. The difference is subtle but important:
Sequelize有着两种不同但相关的与关联相关的scope概念。两者的不同很微弱,但却很重要
- Association scopes Allow you to specify default attributes when getting and setting associations - useful when implementing polymorphic associations. This scope is only invoked on the association between the two models, when using the
get
,set
,add
andcreate
associated model functions当getting和setting关联时,允许你指定属性-当实现多元化关联时十分有用。这个scope只有在两个模型的关联中被调用,使用get
,set
,add
和create
关联模型函数 - Scopes on associated models Allows you to apply default and other scopes when fetching associations, and allows you to pass a scoped model when creating associations. These scopes both apply to regular finds on the model and to find through the association.允许你在获取关联时请求默认或其他scopes,也允许你在创建关联时传递scoped模型。这个scopes即在模型中请求传统查询也通过关联进行查找
As an example, consider the models Post and Comment. Comment is associated to several other models (Image, Video etc.) and the association between Comment and other models is polymorphic, which means that Comment stores a commentable
column, in addition to the foreign key commentable_id
.
举例,考虑模型Post和Comment。Comment与几个模型关联(Image, Video等)且在Comment和其他模型之间的关联是多元化的,这意味着Comment存储commentable
列,除此之外commentable_id
为外键
The polymorphic association can be implemented with an association scope :
多元化关联可以使用关联scope实现:
this.Post.hasMany(this.Comment, { foreignKey: 'commentable_id', scope: { commentable: 'post' } });
When calling post.getComments()
, this will automatically add WHERE commentable = 'post'
. Similarly, when adding new comments to a post, commentable
will automagically be set to 'post'
. The association scope is meant to live in the background without the programmer having to worry about it - it cannot be disabled. For a more complete polymorphic example, see Association scopes
当调用post.getComments()
时,他将自动添加 WHERE commentable = 'post'
。同样的,当添加新comment到post中时,commentable
将会自动设置为 'post'
。关联scope意味着存活在没有项目烦恼的后台-它不可能不可用。更多完成的多元化实例,看 Association scopes。
Consider then, that Post has a default scope which only shows active posts: where: { active: true }
. This scope lives on the associated model (Post), and not on the association like the commentable
scope did. Just like the default scope is applied when calling Post.findAll()
, it is also applied when calling User.getPosts()
- this will only return the active posts for that user.
考虑这些后,Post有了只显示活跃posts:where: { active: true }
的缺省scope。这个scope存活在关联的模型(Post)中,而不在像commentable scope做出的关联中。当调用
Post.findAll()和
时,缺省scopeUser.getPosts()
被请求-将只返回活跃posts
To disable the default scope, pass scope: null
to the getter: User.getPosts({ scope: null })
. Similarly, if you want to apply other scopes, pass an array like you would to .scope
:
为了使缺省scope无效,传递scope: null
给getter: User.getPosts({ scope: null })。相同的,如果你想要请求其他scopes,只要传递数组,就像你传递给
.scope
的那样:
User.getPosts({ scope: ['scope1', 'scope2']});
If you want to create a shortcut method to a scope on an associated model, you can pass the scoped model to the association. Consider a shortcut to get all deleted posts for a user:
如果你想要创建快捷方法去一个关联模型的scope,你可以传递scoped模型给关联。考虑快捷方式将得到所有删除的posts给用户
const Post = sequelize.define('post', attributes, { defaultScope: { where: { active: true } }, scopes: { deleted: { where: { deleted: true } } } }); User.hasMany(Post); // regular getPosts association User.hasMany(Post.scope('deleted'), { as: 'deletedPosts' }); User.getPosts(); // WHERE active = true User.getDeletedPosts(); // WHERE deleted = true