前言:
Sequelize中提供的增刪改查相關的函數都能轉成原生的sql語句。本篇文章介紹一個不是很常見但是有時候批量插入很方便的函數——bulkCreate。
bulkCreate講解
官方文檔理解
bulkCreate() - 創建多條記錄
bulkCreate(records, [options]) -> Promise.<Array.<Instance>>
復制代碼
批量創建並保存多個實例。
處理成功后,會在回調函數中返回一個包含多個實例的數組。
參數
| 名稱 | 類型 | 說明 |
|---|---|---|
| records | Array | 要創建實例的對象(鍵/值 對)列表 |
| [options] | Object | |
| [options.fields] | Array | 要插入的字段。默認全部 |
| [options.validate=true] | Boolean | 插入每條記錄前進行驗證 |
| [options.hooks=true] | Boolean | 在執行前/后創建鈎子 |
| [options.individualHooks=false] | Boolean | 在執行前/后為每個實例創建鈎子 |
| [options.ignoreDuplicates=false] | Boolean | 忽略重復主鍵(Postgres不支持) |
| [options.updateOnDuplicate] | Array | 如果行鍵已存在是否更新(mysql & mariadb支持). 默認為更新 |
| [options.transaction] | Transaction | 在事務中執行查詢 |
注意:options.updateOnDuplicate參數中的行鍵已存在我的理解是:數據庫表中現有的記錄的唯一索引或者主鍵如果已經存在,執行更新操作
對應原生sql語句講解
在MySQL數據庫中,如果在insert語句后面帶上ON DUPLICATE KEY UPDATE 子句。
- 要插入的行與表中現有記錄的惟一索引或主鍵中產生重復值,那么就會發生舊行的更新;
- 如果插入的行數據與現有表中記錄的唯一索引或者主鍵不重復,則執行新紀錄插入操作。
await CompositionAnswer.bulkCreate(answerList, { updateOnDuplicate: ['answer', 'updatedAt'] })
以上代碼可以實現插入多個數據時,若其中有重復的數據,只對 answer和updatedAt進行更新。
那么關鍵來了,怎么判定數據重復,如果我不想使用表的默認主鍵(比如id),怎么辦?
答案就是 ,設置unique索引!!!
static options = { indexes: [ { name: 'composition_answer_index', fields: [ 'exercise_id' ] }, { name: 'composition_answer_index_unique', unique: true, fields: ['exercise_id', 'question_id', 'question_material_id'] } ] } static init (sequelize) { super.init({ sequelize, attributes: this.attributes, tableName: 'composition_answer', options: this.options }) }
composition_answer_index_unique 就是我們的唯一索引,當出現重復的數據時,不會進行插入,而是更新。
但是sequelize對於uniqueKeys設置有bug(目前最新版本6.2.3),只到上邊那一步時,bulkCreate時還是沒有識別到唯一索引。
hack方式就是,在attributes的字段,設置上 索引名稱。
static attributes = { exerciseId: { unique: 'composition_answer_index_unique', //就是他!!! type: DataTypes.INTEGER, field: 'exercise_id' }, questionId: { unique: 'composition_answer_index_unique', // 和他!!! type: DataTypes.INTEGER, field: 'question_id' }, questionMaterialId: { unique: 'composition_answer_index_unique', // 還有他!!! type: DataTypes.INTEGER, field: 'question_material_id', allowNull: true } }
