Ash*_*osh 21 node.js sequelize.js
有没有办法在sequelize中进行批量upsert.另外,我可以指定用于检查重复的密钥.
我试过以下但没有奏效:
Employee.bulkCreate(data, {
updateOnDuplicate: true
});
Run Code Online (Sandbox Code Playgroud)
批量创作工作正常.上面的语句总是在DB中创建新条目.
小智 36
来自官方sequelizejs参考.
这是可以做到用bulkCreate
与updateOnDuplicate
选项.
像这样例如:
Employee.bulkCreate(dataArray,
{
fields:["id", "name", "address"] ,
updateOnDuplicate: ["name"]
} )
Run Code Online (Sandbox Code Playgroud)
updateOnDuplicate
是一个字段数组,当主键(或可能是唯一键)与行匹配时将更新这些字段.确保模型中至少有一个唯一的字段(比如说id),并且dataArray
两者都有upsert.
由于答案不支持PostgreSQL,因此使用Sequelize的“”“”“ best”“”“替代方案将使用该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 })
Run Code Online (Sandbox Code Playgroud)
这将建立一个查询,例如:
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;
Run Code Online (Sandbox Code Playgroud)
可以说,这不是必须手动构建查询的理想解决方案,因为它违反了使用sequelize的目的,但是,如果您不需要的是一次性查询,则可以使用此方法。
2019年更新
适用于所有方言,前提是匹配某个最低版本
这是对相同内容的源代码的引用
请注意,各个选项可能适用于所有方言,也可能不适用于例如 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.'));
}
Run Code Online (Sandbox Code Playgroud)
updateOnDuplicate 必须是一个数组,不能为 true 或 false
因此,根据上述几点,您的代码应该是这样的
Employee.bulkCreate(data, {
updateOnDuplicate: ['employeeName', 'employeeAge'],
});
Run Code Online (Sandbox Code Playgroud)
更新:
既然有人提到它不起作用,请尝试这个
models.Employee.bulkCreate(items, {
returning: ['employeeId'],
ignoreDuplicates: true
})
Run Code Online (Sandbox Code Playgroud)
2020年10月1日更新
续集版本:^6.3.5
该问题仍然存在。我们仍然不能bulkUpsert
使用唯一的复合索引。bulkCreate
withupdateOnDuplicates
尚不支持唯一复合索引。还有 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;
}
};
Run Code Online (Sandbox Code Playgroud)
重要的一点是bulkUpsertableData
在它应该在的地方创建Array<Array> ie:- [[]]
。创建示例:-
// with reference to above wrapper function
const bulkUpsertableData = Object.keys(myObjectData).map(type => [
myObjectData[type],// -----> non_id_attr1
type, // -----> non_id_attr2
someOtherRandomValue, // -----> non_id_attr3
new Date(), // -----> created_at
new Date(), // -----> updated_at
]);
// response will have all the raw attributes mentioned in RETURNING clause
const upsertedTableResponse = await bulkUpsertIntoTable({ bulkUpsertableData });
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
13229 次 |
最近记录: |