Nodejs续集大量upsert

时间:2018-01-06 06:41:29

标签: node.js sequelize.js

有没有办法在续集中进行批量upsert。另外,我可以指定用于检查重复的密钥。

我试过以下但没有奏效:

Employee.bulkCreate(data, {
    updateOnDuplicate: true
});

批量创作工作正常。上面的语句总是在DB中创建新条目。

5 个答案:

答案 0 :(得分:22)

来自官方Custom Headers

可以使用updateOnDuplicate选项Employee.bulkCreate(dataArray, { fields:["id", "name", "address"] , updateOnDuplicate: ["name"] } ) 来完成。

就像这样:

updateOnDuplicate

dataArray是一个字段数组,当主键(或可能是唯一键)与行匹配时,这些字段将被更新。确保模型中至少有一个唯一字段(比方说id), btnSave.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) { createWebPrintJob(webView); } else { } } }); 中的唯一字段用于upsert。

答案 1 :(得分:3)

由于答案不支持PostgreSQL,因此使用Sequelize的““”“”最佳“”“”替代方法是使用ON CONFLICT语句进行手动查询。示例(打字稿):

const values: Array<Array<number | string>> = [
    [1, 'Apple', 'Red', 'Yummy'],
    [2, 'Kiwi', 'Green', 'Yuck'],
]

const query = 'INSERT INTO fruits (id, name, color, flavor) VALUES ' +
     values.map(_ => { return '(?)' }).join(',') +
     ' ON CONFLICT (id) DO UPDATE SET flavor = excluded.flavor;'

sequelize.query({ query, values }, { type: sequelize.QueryTypes.INSERT })

这将建立一个查询,例如:

INSERT INTO 
    fruits (id, name, color, flavor)
VALUES 
    (1, 'Apple', 'Red', 'Yummy'),
    (2, 'Kiwi', 'Green', 'Yuck')
ON CONFLICT (id) DO UPDATE SET 
    flavor = excluded.flavor;

可以说,这不是必须手动构建查询的理想解决方案,因为它违反了使用序列化的目的,但是,如果您不需要的是一次性查询,则可以使用此方法。

答案 2 :(得分:1)

2019更新

适用于所有方言,只要满足特定的最低版本要求

HERE是对同一源代码的引用

  • 请注意,个别选项可能适用于所有方言,也可能无法适用于所有方言 例如,updateOnDuplicate仅在MySQL,MariaDB, SQLite和Postgres

  • ignoreDuplicates选项在MSSQL上不起作用

还要在源代码中检查此代码块

if (Array.isArray(options.updateOnDuplicate) && options.updateOnDuplicate.length) {
    options.updateOnDuplicate = _.intersection(
        _.without(Object.keys(model.tableAttributes), createdAtAttr),
        options.updateOnDuplicate
    );
} else {
    return Promise.reject(new Error('updateOnDuplicate option only supports non-empty array.'));
}

updateOnDuplicate必须是一个数组,不能为true或false

根据以上几点,您的代码应该是这样的

Employee.bulkCreate(data, {
    updateOnDuplicate: ['employeeName', 'employeeAge'],
});

更新:

由于有人提到它不起作用,请尝试

models.Employee.bulkCreate(items, {
    returning: ['employeeId'],
    ignoreDuplicates: true
  })

答案 3 :(得分:1)

2020年10月1日更新
续集版本:^ 6.3.5

问题仍然存在。我们仍然无法bulkUpsert使用唯一的复合索引。 bulkCreateupdateOnDuplicates尚不适用于唯一的复合索引。还有PR正在等待合并,这可能会解决此问题:-
https://github.com/sequelize/sequelize/pull/12516
https://github.com/sequelize/sequelize/pull/12547

解决方法

目前,如果有人想快速解决问题,则可以通过使用自己的表属性,名称和数据进行修改来使用以下基于原始查询的包装器:-

const bulkUpsertIntoTable = async ({ bulkUpsertableData }) => {
  try {
    /* eslint-disable */
   // id column will automatically be incremented if you have set it to auto-increment
   const query = `INSERT INTO "Table" ("non_id_attr1", "non_id_attr2", "non_id_attr3","createdAt", "updatedAt") VALUES ${bulkUpsertableData
    .map((_) => "(?)")
    .join(
      ","
    )} ON CONFLICT ("non_id_attr1","non_id_attr2") DO UPDATE SET "non_id_attr1"=excluded."non_id_attr1", "non_id_attr2"=excluded."non_id_attr2", "non_id_attr3"=excluded."non_id_attr3",  "updatedAt"=excluded."updatedAt" RETURNING "id","non_id_attr1","non_id_attr2","non_id_attr3","createdAt","updatedAt";`;
    /* eslint-enable */

    return await models.sequelize.query(query, {
      replacements: bulkUpsertableData,//------> dont forget to pass your data here
      type: models.Sequelize.QueryTypes.INSERT,
      // transaction:t -----> if required to be done in transaction
    });
  } catch (error) {
    console.error("Bulk Upserting into Table:", error);
    throw error;
  }
};

重要的一点是创建bulkUpsertableData 。创建示例:-

Array<Array> ie:- [[]]

答案 4 :(得分:0)

2020年11月2日更新

基于@Yedhin答案,这是一个更通用的解决方案(打字稿):

let url = URL(string: "http://192.168.1.318:8080")! /*localhost*/
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.httpBody = jsonData
request.cachePolicy = .reloadIgnoringLocalAndRemoteCacheData
// or
request.cachePolicy = .reloadIgnoringCacheData