Sequelize-nodejs-9-Scopes
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