Node.js Nodejs续集批量升级
在sequelize中是否有进行批量升级的方法。另外,我可以指定用于检查重复项的键吗 我尝试了以下操作,但不起作用:Node.js Nodejs续集批量升级,node.js,sequelize.js,Node.js,Sequelize.js,在sequelize中是否有进行批量升级的方法。另外,我可以指定用于检查重复项的键吗 我尝试了以下操作,但不起作用: Employee.bulkCreate(data, { updateOnDuplicate: true }); 不过,批量创作效果很好。上述语句总是在数据库中创建新条目。来自官方 可以使用bulkCreate和updateOnDuplicate选项来完成 例如: Employee.bulkCreate(dataArray, { fields:[
Employee.bulkCreate(data, {
updateOnDuplicate: true
});
不过,批量创作效果很好。上述语句总是在数据库中创建新条目。来自官方
可以使用bulkCreate
和updateOnDuplicate
选项来完成
例如:
Employee.bulkCreate(dataArray,
{
fields:["id", "name", "address"] ,
updateOnDuplicate: ["name"]
} )
updateOnDuplicate
是一个字段数组,当主键(或可能是唯一键)与行匹配时,这些字段将被更新。确保您的模型和dataArray
中至少有一个唯一字段(比如id)用于upsert。更新
Sequelize 6.x增加了对所有方言的所有Upsert的支持,因此@followtest52的答案也适用于PostgreSQL
起初的
由于答案不支持PostgreSQL,因此使用Sequelize的“最佳”替代方法是使用该语句进行手动查询。示例(类型脚本):
可以说,这并不是手动构建查询的理想解决方案,因为它不符合使用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.'));
}
updateOnDuplicate必须是数组,不能为true或false
根据以上几点,您的代码应该是这样的
Employee.bulkCreate(data, {
updateOnDuplicate: ['employeeName', 'employeeAge'],
});
更新:
既然有人提到它不起作用,试试这个
models.Employee.bulkCreate(items, {
returning: ['employeeId'],
ignoreDuplicates: true
})
2020年10月1日更新
续集版本:^6.3.5
问题仍然存在。我们仍然无法使用唯一的复合索引插入bulkupert
bulkCreate
withupdateOnDuplicates
还不能使用唯一的复合索引。还有一些PR仍在等待合并,这可能会解决此问题:-变通办法 目前,如果有人想快速解决问题,那么可以通过修改您自己的表属性、名称和数据来使用以下基于原始查询的包装器:-
const bulkupsertinotable=async({bulkUpsertableData})=>{
试一试{
/*eslint禁用*/
//如果将id列设置为“自动递增”,它将自动递增
const query=`INSERT-INTO“Table”(“non_id_attr1”、“non_id_attr2”、“non_id_attr3”、“createdAt”、“updatedAt”)值${bulkUpsertableData
.map(())=>“(?)”)
.加入(
","
)}冲突时(“非id属性1”、“非id属性2”)更新集“非id属性1”=排除。“非id属性1”、“非id属性2”=排除。“非id属性2”、“非id属性3”=排除。“非id属性3”、“更新数据”=排除。“更新数据”返回“id”、“非id属性1”、“非id属性2”、“非id属性3”、“创建数据”、“更新数据”;`;
/*eslint使能*/
return wait models.sequelize.query(查询{
替换:bulkUpsertableData,//-->不要忘记在此处传递数据
类型:models.Sequelize.QueryTypes.INSERT,
//交易:t----->如果需要在交易中完成
});
}捕获(错误){
控制台错误(“批量升级到表:”,错误);
投掷误差;
}
};
重要的一点是创建bulkUpsertableData
,它应该位于数组中,即:-[[]]
。创建示例:-
//参考上述包装函数
const bulkUpsertableData=Object.keys(myObjectData.map)(类型=>[
myObjectData[类型],/->非id属性1
类型,//--->non\u id\u attr2
someOtherRandomValue,//--->非\u id\u attr3
新建日期(),//------>创建于
新日期(),//--->更新时间
]);
//响应将具有RETURNING子句中提到的所有原始属性
const upsertedTableResponse=等待bulkupsertinotable({bulkUpsertableData});
2020年11月2日更新
基于@Yedhin answer,这里有一个更通用的解决方案(typescript):
导出常量bulkUpsert=async(
项目:部分[],
型号:ModelCtor,
冲突键:K[],
excludeFromUpdate:K[]=[],
):承诺=>{
如果(!items.length){
返回[0,0];
}
const{tableName,sequelize,name}=model;
如果(!续集){
抛出新错误(`Sequelize not initialized on${name}?`);
}
常量样本=项目[0];
常量字段=对象。键(示例)为K[];
常量createFields=`(${fields.join(`,“`}”)`;
const updateFields=字段
.filter((字段)=>![…excludeFromUpdate,…conflictKeys]。包括(字段))
.map((字段)=>`${field}'=已排除。${field}`)
。加入(‘,’);
const values=items.map(dataToSql(sequelize)).join(',');
const onConflict=`ON CONFLICT(${conflictKeys.join(`,“`}”)`;
const returning=`${fields.join(“,”)}`;
const query=`插入“${tableName}”${createFields}值${VALUES}${onConflict}DO UPDATE SET${updateFields}返回${RETURNING};`;
返回sequelize.query(查询{
替换:项目,
类型:QueryTypes.INSERT,
});
};
const valueToSql=(sequelize:sequelize)=>(
值:string | number | boolean | null | Date | string[]|记录,
):string=>{
如果(值===null){
返回'null';
}
如果(值的类型=='boolean'){
返回值?'true':'false';
}
if(值的类型!='object'| |日期的值实例){
返回sequelize.escape(值);
}
返回sequelize.escape(JSON.stringify(value));
};
const dataToSql=(sequelize:sequelize)=>(数据:部分):字符串=>
`(${Object.values(data.map(valueToSql(sequelize)).join(',')})`;
谢谢
Employee.bulkCreate(data, {
updateOnDuplicate: ['employeeName', 'employeeAge'],
});
models.Employee.bulkCreate(items, {
returning: ['employeeId'],
ignoreDuplicates: true
})
export const bulkUpsert = async <T extends Model<T>, K extends keyof T>(
items: Partial<T>[],
model: ModelCtor<T>,
conflictKeys: K[],
excludeFromUpdate: K[] = [],
): Promise<[number, number]> => {
if (!items.length) {
return [0, 0];
}
const { tableName, sequelize, name } = model;
if (!sequelize) {
throw new Error(`Sequelize not initialized on ${name}?`);
}
const sample = items[0];
const fields = Object.keys(sample) as K[];
const createFields = `("${fields.join(`","`)}")`;
const updateFields = fields
.filter((field) => ![...excludeFromUpdate, ...conflictKeys].includes(field))
.map((field) => `"${field}"=EXCLUDED."${field}"`)
.join(', ');
const values = items.map(dataToSql(sequelize)).join(',');
const onConflict = `ON CONFLICT ("${conflictKeys.join(`","`)}")`;
const returning = `"${fields.join('","')}"`;
const query = `INSERT INTO "${tableName}" ${createFields} VALUES ${values} ${onConflict} DO UPDATE SET ${updateFields} RETURNING ${returning};`;
return sequelize.query(query, {
replacements: items,
type: QueryTypes.INSERT,
});
};
const valueToSql = (sequelize: Sequelize) => (
value: string | number | boolean | null | Date | string[] | Record<string, unknown>,
): string => {
if (value === null) {
return 'null';
}
if (typeof value === 'boolean') {
return value ? 'true' : 'false';
}
if (typeof value !== 'object' || value instanceof Date) {
return sequelize.escape(value);
}
return sequelize.escape(JSON.stringify(value));
};
const dataToSql = <T extends Node<T>>(sequelize: Sequelize) => (data: Partial<T>): string =>
`(${Object.values(data).map(valueToSql(sequelize)).join(',')})`;