Node.js Nodejs续集批量升级

Node.js Nodejs续集批量升级,node.js,sequelize.js,Node.js,Sequelize.js,在sequelize中是否有进行批量升级的方法。另外,我可以指定用于检查重复项的键吗 我尝试了以下操作,但不起作用: Employee.bulkCreate(data, { updateOnDuplicate: true }); 不过,批量创作效果很好。上述语句总是在数据库中创建新条目。来自官方 可以使用bulkCreate和updateOnDuplicate选项来完成 例如: Employee.bulkCreate(dataArray, { fields:[

在sequelize中是否有进行批量升级的方法。另外,我可以指定用于检查重复项的键吗

我尝试了以下操作,但不起作用:

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
with
updateOnDuplicates
还不能使用唯一的复合索引。还有一些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(',')})`;