1. 程式人生 > >Sequelize-nodejs-9-Scopes

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。這對帶有includesscopes十分有用,因為在其他模型被定義時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, attributeswhere定義。使用上面的例子並在包含的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複寫limitage,當firstName儲存時。whereinclude被淺合併時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 and create associated model functions當getting和setting關聯時,允許你指定屬性-當實現多元化關聯時十分有用。這個scope只有在兩個模型的關聯中被呼叫,使用get, set, addcreate關聯模型函式
  • 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()和User.getPosts()時,預設scope被請求-將只返回活躍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: nullgetter: 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