Sequelize Upsert正在创建而不是更新

gdrx4gfi  于 2022-10-31  发布在  Mysql
关注(0)|答案(2)|浏览(187)

根据这里找到的文档,它声明如下
upsert(values, [options]) -> Promise.<created>
插入或更新单个行。如果找到与主键或唯一键上提供的值匹配的行,则将执行更新。请注意,必须在sequelize模型中定义唯一索引,而不仅仅是在表中。否则,您可能会遇到违反唯一约束条件的情况,因为sequelize无法标识应更新的行。
所以我的期望是使用唯一键的upsert应该替换现有的值。然而当我的代码运行而不是更新现有的数据库记录时,它添加了一个新的记录。我做错了什么?
这是我模型的一个样本

'use strict'

module.exports = (db, dataTypes) => {
  const titanJob = db.define('titanJob', {
    titanId: {
      type: dataTypes.STRING,
      allowNull: false,
      unique: true
    },
    name: {
      type: dataTypes.STRING,
      allowNull: false
    }
  }, {
    timestamps: true
  })
  return titanJob
}

这是我的一个例子

await asyncForEach(res.data.hits.hits, async es => {
  const src = es._source
  try {
    await titanJob.upsert({
      name: src.name,
      titanId: src.id,
    }, { titanId: src.id })
    logger.debug(`[${file}] upsert successful`)
  } catch (err) {
    logger.warn(`[${file}] failed to save to database`)
    logger.warn(`[${file}] ${err}`)
  }
})
dsekswqp

dsekswqp1#

首先,您应该在数据表中加入唯一索引(条件约束)。您插入的数据应该包含唯一索引(条件约束)的字段集。

tv6aics1

tv6aics12#

下面是一个使用"sequelize": "^5.21.3"的示例:
index.ts

import { Model, DataTypes } from 'sequelize';
import { sequelize } from '../../db';
import assert from 'assert';

class TitanJob extends Model {}
TitanJob.init(
  {
    titanId: {
      type: DataTypes.STRING,
      allowNull: false,
      unique: true,
    },
    name: {
      type: DataTypes.STRING,
      allowNull: false,
    },
  },
  { sequelize, modelName: 'titanJob', timestamps: true },
);

(async function test() {
  try {
    await sequelize.sync({ force: true });
    const datas = [
      { titanId: '1', name: 'programmer' },
      { titanId: '2', name: 'teacher' },
    ];
    const jobs = await TitanJob.bulkCreate(datas);
    assert.deepEqual(
      jobs.map((job) => ({ titanId: job.id, name: job.name })),
      datas,
      'Should bulk create programmer and teacher datas',
    );
    const rval = await TitanJob.upsert({ titanId: '1', name: 'driver' }, { returning: true });
    assert.equal(rval[0].titanId, '1', 'Should update the row which titanId is "1"');
  } catch (error) {
    console.log(error);
  } finally {
    await sequelize.close();
  }
})();

执行结果:

{ POSTGRES_HOST: '127.0.0.1',
  POSTGRES_PORT: '5430',
  POSTGRES_PASSWORD: 'testpass',
  POSTGRES_USER: 'testuser',
  POSTGRES_DB: 'node-sequelize-examples' }
Executing (default): DROP TABLE IF EXISTS "titanJob" CASCADE;
Executing (default): DROP TABLE IF EXISTS "titanJob" CASCADE;
Executing (default): CREATE TABLE IF NOT EXISTS "titanJob" ("id"   SERIAL , "titanId" VARCHAR(255) NOT NULL UNIQUE, "name" VARCHAR(255) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL, PRIMARY KEY ("id"));
Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'titanJob' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Executing (default): INSERT INTO "titanJob" ("id","titanId","name","createdAt","updatedAt") VALUES (DEFAULT,'1','programmer','2020-02-14 08:09:45.506 +00:00','2020-02-14 08:09:45.506 +00:00'),(DEFAULT,'2','teacher','2020-02-14 08:09:45.506 +00:00','2020-02-14 08:09:45.506 +00:00') RETURNING *;
Executing (default): CREATE OR REPLACE FUNCTION pg_temp.sequelize_upsert(OUT created boolean, OUT primary_key text)  AS $func$ BEGIN INSERT INTO "titanJob" ("titanId","name","createdAt","updatedAt") VALUES ('1','driver','2020-02-14 08:09:45.524 +00:00','2020-02-14 08:09:45.524 +00:00') RETURNING "id" INTO primary_key; created := true; EXCEPTION WHEN unique_violation THEN UPDATE "titanJob" SET "titanId"='1',"name"='driver',"updatedAt"='2020-02-14 08:09:45.524 +00:00' WHERE ("id" IS NULL OR "titanId" = '1') RETURNING "id" INTO primary_key; created := false; END; $func$ LANGUAGE plpgsql; SELECT * FROM pg_temp.sequelize_upsert();
Executing (default): SELECT "id", "titanId", "name", "createdAt", "updatedAt" FROM "titanJob" AS "titanJob" WHERE "titanJob"."id" = '1';

没有Assert失败。它按预期工作。请检查数据库中的数据行:

node-sequelize-examples=# select * from "titanJob";
 id | titanId |  name   |         createdAt          |         updatedAt
----+---------+---------+----------------------------+----------------------------
  2 | 2       | teacher | 2020-02-14 08:09:45.506+00 | 2020-02-14 08:09:45.506+00
  1 | 1       | driver  | 2020-02-14 08:09:45.506+00 | 2020-02-14 08:09:45.524+00
(2 rows)

源代码:https://github.com/mrdulin/node-sequelize-examples/tree/master/src/examples/stackoverflow/59686743

相关问题