Sequelize 中文文檔 v4 -Scopes - 做用域

Scopes - 做用域

此係列文章的應用示例已發佈於 GitHub: sequelize-docs-Zh-CN. 能夠 Fork 幫助改進或 Star 關注更新. 歡迎 Star.html

做用域容許你定義經常使用查詢,以便之後輕鬆使用。 做用域能夠包括與常規查找器 where, include, limit 等全部相同的屬性。git

定義

做用域在模型定義中定義,能夠是finder對象或返回finder對象的函數,除了默認做用域,該做用於只能是一個對象:程序員

const Project = sequelize.define('project', {
  // 屬性
}, {
  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
          }
        }
      }
    }
  }
});

經過調用 addScope 定義模型後,還能夠添加做用域。 這對於具備包含的做用域特別有用,其中在定義其餘模型時可能不會定義 include 中的模型。github

始終應用默認做用域。 這意味着,經過上面的模型定義,Project.findAll() 將建立如下查詢:sql

SELECT * FROM projects WHERE active = true

能夠經過調用 .unscoped(), .scope(null) 或經過調用另外一個做用域來刪除默認做用域:數組

Project.scope('deleted').findAll(); // 刪除默認做用域
SELECT * FROM projects WHERE deleted = true

還能夠在做用域定義中包含做用域模型。 這讓你避免重複 includeattributeswhere 定義。dom

使用上面的例子,並在包含的用戶模型中調用 active 做用域(而不是直接在該 include 對象中指定條件):函數

activeUsers: {
  include: [
    { model: User.scope('active')}
  ]
}

使用

經過在模型定義上調用 .scope 來應用做用域,傳遞一個或多個做用域的名稱。 .scope 返回一個全功能的模型實例,它具備全部常規的方法:.findAll.update.count.destroy等等。你能夠保存這個模型實例並稍後再次使用:post

const DeletedProjects = Project.scope('deleted');

DeletedProjects.findAll();
// 過一段時間

// 讓咱們再次尋找被刪除的項目!
DeletedProjects.findAll();

做用域適用於 .find, .findAll, .count, .update.destroy.this

能夠經過兩種方式調用做爲函數的做用域。 若是做用域沒有任何參數,它能夠正常調用。 若是做用域採用參數,則傳遞一個對象:

Project.scope('random', { method: ['accessLevel', 19]}).findAll();
SELECT * FROM projects WHERE someNumber = 42 AND accessLevel >= 19

合併

經過將做用域數組傳遞到 .scope 或經過將做用域做爲連續參數傳遞,能夠同時應用多個做用域。

// 這兩個是等價的
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

若是要將其餘做用域與默認做用域一塊兒應用,請將鍵 defaultScope 傳遞給 .scope

Project.scope('defaultScope', 'deleted').findAll();
SELECT * FROM projects WHERE active = true AND deleted = true

當調用多個做用域時,後續做用域的鍵將覆蓋之前的做用域(相似於 _.assign )。 考慮兩個做用域:

{
  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 覆蓋 limitage,而 firstName 被保留。 limitoffsetorderparanoidlockraw被覆蓋,而whereinclude被淺層合併。 這意味着相同的鍵在同一個模型的對象以及隨後的包含都將相互覆蓋。

當將查找對象直接傳遞到做用域模型上的 findAll 時,適用相同的合併邏輯:

Project.scope('deleted').findAll({
  where: {
    firstName: 'john'
  }
})
WHERE deleted = true AND firstName = 'john'

這裏的 deleted 做用域與 finder 合併。 若是咱們要將 where: { firstName: 'john', deleted: false } 傳遞給 finder,那麼 deleted 做用域將被覆蓋。

關聯

Sequelize 與關聯有兩個不一樣但相關的做用域概念。 差別是微妙但重要的:

  • 關聯做用域 容許您在獲取和設置關聯時指定默認屬性 - 在實現多態關聯時頗有用。 當使用getsetaddcreate相關聯的模型函數時,這個做用域僅在兩個模型之間的關聯上被調用
  • 關聯模型上的做用域 容許您在獲取關聯時應用默認和其餘做用域,並容許您在建立關聯時傳遞做用域模型。 這些做用域都適用於模型上的常規查找和經過關聯查找。

舉個例子,思考模型Post和Comment。 註釋與其餘幾個模型(圖像,視頻等)相關聯,註釋和其餘模型之間的關聯是多態的,這意味着除了外鍵 commentable_id 以外,註釋還存儲一個commentable列。

可使用 association scope 來實現多態關聯:

this.Post.hasMany(this.Comment, {
  foreignKey: 'commentable_id',
  scope: {
    commentable: 'post'
  }
});

當調用 post.getComments() 時,這將自動添加 WHERE commentable = 'post'。 相似地,當向帖子添加新的註釋時,commentable 會自動設置爲 'post'。 關聯做用域是爲了存活於後臺,沒有程序員沒必要擔憂 - 它不能被禁用。 有關更完整的多態性示例,請參閱 關聯做用域

那麼考慮那個Post的默認做用域只顯示活動的帖子:where: { active: true }。 該做用域存在於相關聯的模型(Post)上,而不是像commentable 做用域那樣在關聯上。 就像在調用Post.findAll() 時同樣應用默認做用域,當調用 User.getPosts() 時,它也會被應用 - 這隻會返回該用戶的活動帖子。

要禁用默認做用域,將 scope: null 傳遞給 getter: User.getPosts({ scope: null })。 一樣,若是要應用其餘做用域,請像這樣:

User.getPosts({ scope: ['scope1', 'scope2']});

若是要爲關聯模型上的做用域建立快捷方式,能夠將做用域模型傳遞給關聯。 考慮一個快捷方式來獲取用戶全部已刪除的帖子:

const Post = sequelize.define('post', attributes, {
  defaultScope: {
    where: {
      active: true
    }
  },
  scopes: {
    deleted: {
      where: {
        deleted: true
      }
    }
  }
});

User.hasMany(Post); // 常規 getPosts 關聯
User.hasMany(Post.scope('deleted'), { as: 'deletedPosts' });
User.getPosts(); // WHERE active = true
User.getDeletedPosts(); // WHERE deleted = true

若是這篇文章對您有幫助, 感謝 下方點贊 或 Star GitHub: sequelize-docs-Zh-CN 支持, 謝謝.

相關文章
相關標籤/搜索