Я сталкиваюсь с уникальной проблемой нарушения ограничений при выполнении upsert, потому что запрос UPDATE
, созданный sequelize, игнорирует ограничение частичного индекса, определенное моделью (если это не имеет значения). Я новичок в node + sequelize, поэтому я мог упустить что-то очевидное, но я обошел все возможные места для поиска подходящих ответов, включая код sequelize, но я не смог найти ответ, который ищу за. Очень ценю вашу помощь!
Мои текущие версии:
"pg": "7.9.0",
"sequelize": "5.21.3"
У меня есть модель, состоящая из первичного ключа: id
и двух других уникальных индексов, один из которых является пустым полем.
module.exports.Entities = sequelize.define('entities', {
id: {type: Sequelize.UUID, defaultValue: Sequelize.UUIDV4, allowNull: false, primaryKey: true},
cId: {type: Sequelize.STRING, allowNull: false},
pId: {type: Sequelize.UUID, allowNull: false},
eKey: {type: Sequelize.INTEGER, allowNull: true}
}, {
indexes: [
{
name: 'unique_c_id_p_id',
fields: ['c_id', 'p_id'],
unique: true
},
{
name: 'unique_e_key',
fields: ['e_key'],
unique: true,
where: {
eKey: {
[Op.not]: null
}
}
}
]
})
и сама таблица выглядит следующим образом:
CREATE TABLE public.entities (
id UUID DEFAULT uuid_generate_v4 (),
c_id UUID NOT NULL,
p_id UUID NOT NULL,
e_key INTEGER DEFAULT NULL,
CONSTRAINT ENTITY_SERVICE_PKEY PRIMARY KEY (id),
CONSTRAINT unique_c_id_p_id UNIQUE (c_id, p_id)
);
CREATE UNIQUE INDEX unique_e_key ON public.entities (e_key) WHERE e_key IS NOT NULL;
Вызов метода upsert выглядит следующим образом:
module.exports.upsert = async (Model, values) => Model.upsert(values, {returning: true})
Я пропускаю вышеуказанную Entities
модель и приведенное ниже значение в качестве аргументов этой функции.
{
"id"="3169d4e2-8e2d-451e-8be0-40c0b28e2aa9",
"c_id"="00000000-0000-0000-0000-000000000000",
"p_id"="78bce392-4a15-4a8a-986b-c9398787345f",
"e_key"= null
}
Issue : SequelizeUniqueConstraintError
Sequelize пытается выполнить вставку с последующим запросом на обновление, когда мы пытаемся обновить существующий запись с использованием метода upsert. Запрос вставки показывает конфликт, так как запись уже существует, и продолжение вызова upsert продолжает вызывать запрос на обновление.
Однако запрос, который он строит в UPDATE
, выглядит примерно так:
"SQL statement UPDATE entities SET id='3169d4e2-8e2d-451e-8be0-40c0b28e2aa9',c_id='00000000-0000-0000-0000-000000000000',p_id='78bce392-4a15-4a8a-986b-c9398787345f',e_key=NULL
WHERE (id = '3169d4e2-8e2d-451e-8be0-40c0b28e2aa9'
OR e_key IS NULL
OR (c_id = '00000000-0000-0000-0000-000000000000' AND p_id = '78bce392-4a15-4a8a-986b-c9398787345f'))
RETURNING id\nPL/pgSQL function pg_temp_5.sequelize_upsert() line 1 at SQL statement"
Теперь я понимаю причину, по которой он генерирует уникальное нарушение ограничения, так как в приведенном выше запросе WHERE
предложение секвелирует вызовы OR e_key IS NULL
, поскольку e_key = null, и это может потенциально вернуть более 1 записи, и SET
пытается обновить одно и то же значение для всех тех записей, которые были возвращены, тем самым нарушая ограничения primaryKey, ограничения уникальности и т. д. c.
Я хотел бы понять, что:
- Почему sequelize не исключает уникальное ограничение
e_key
, основанное на определенном частичном индексе, учитывая, что оно выбирает атрибуты предложения WHERE
на основе ограничений, определенных в модели и ее индексах? - Могу ли я что-нибудь сделать, чтобы обойти эту проблему?
- Или я пропускаю что-то очевидное, что я могу исправить и попробовать?
Действительно ценю, что вы нашли время, чтобы прочитать и ответить. Спасибо!