-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
BulkCreate with composite unique constraint does not work #11569
Comments
It is not clear why line Line 2705 in 3517eb7
length === 1 .
I have locally added a patch to allow an explicit option to be set called
Can be called like: Bar.bulkCreate([... data ...], {
updateOnDuplicate: [ ... fields to update ... ],
// upsertOn: "unique_timestamp_per_foo", -> unique composite key string from model def
// upsertOn: ['FooId', 'timestamp'] -> fields that have a unique composite key
}) Let me know if you agree, and want me to make a PR with this enhancement. This has solved the gap of not allowing composite unique keys with Replacing these existing lines: Lines 2701 to 2708 in 2b9baa2
With: // Map updateOnDuplicate attributes to fields
if (options.updateOnDuplicate) {
options.updateOnDuplicate = options.updateOnDuplicate.map(attr => model.rawAttributes[attr].field || attr);
// If `upsertOn` is passed as a `bulkCreate` option (allows explicit mapping of `upsertKeys`)
if (Object.prototype.hasOwnProperty.call(options, 'upsertOn')) {
// If a string is passed will search for "custom" unique constraint names.
if (typeof options.upsertOn === 'string' || options.upsertOn instanceof String) {
if (Object.keys(model.uniqueKeys).length > 0) {
options.upsertKeys = _.chain(model.uniqueKeys).values().filter(c => c.customIndex).find(c => c.name === options.upsertOn).get('fields').value();
}
// If an array of `fieldNames` are passed, will check for existence of unique contraint of those fields
// Or it that field exists in a primary key.
} else if (Array.isArray(options.upsertOn) && options.upsertOn.length) {
if (!_.difference(options.upsertOn, Object.keys(model.tableAttributes)).length) {
// Convert upsertOn 'fieldName' array into `field` values.
const _upsertOnFields = options.upsertOn.map(c => model.tableAttributes[c].field);
if (options.upsertOn.length === 1) {
const _upsertKey = _.chain(model.primaryKeys).values().find(c => c.field === _upsertOnFields[0]).get('field').value();
if (_upsertKey) {
options.upsertKeys = [_upsertKey];
}
} else if (Object.keys(model.uniqueKeys).length > 0) {
options.upsertKeys = _.chain(model.uniqueKeys).values().find(c => _.isEqual(c.fields.sort(), _upsertOnFields.sort())).get('fields').value();
}
}
} else {
throw Error('upsertOn option must be an Array or String.');
}
}
if (options.upsertKeys === undefined) {
// Get primary keys for postgres to enable updateOnDuplicate
options.upsertKeys = _.chain(model.primaryKeys).values().map('field').value();
if (Object.keys(model.uniqueKeys).length > 0) {
options.upsertKeys = _.chain(model.uniqueKeys).values().filter(c => c.fields.length === 1).map('column').value();
}
}
} |
Code in fork here: cjancsar@45f6792 |
@papb is this a useful feature? Should I make a PR? |
Note: this doesn't work for composite keys with a partial index, where you need to specify ON CONFLICT ("a","b") WHERE "deleted_at" IS NULL, for example. |
@papb I have a fix working for my use case where I allow the user to specify |
I have same issue. Seems this issue is duplicate of #11534 |
@Rochet2 I've created a patch for my fix: https://gist.github.com/fnimick/5dd3c6855cea6e000c86d1bc38876958 PR coming shortly. |
…eateOptions` This allows the use of a unique index for a `bulkCreate` with `updateOnDuplicate` set, in postgres. The unique index may be a partial index. Closes sequelize#11534, sequelize#11569
…eateOptions` This allows the use of a unique index for a `bulkCreate` with `updateOnDuplicate` set, in postgres. The unique index may be a partial index. Closes sequelize#11534, sequelize#11569
Hi everyone, sorry for taking long, I will take a look at the PR by @fnimick now. Is it the same as the work by @cjancsar? |
@papb no it is not, but I have not had time to create a PR with my work. @fnimick work is a subfeature of the feature that my patch would add (his add ability for partial index as well). I prefer my approach as it only introduces one option |
…eateOptions` This allows the use of a unique index for a `bulkCreate` with `updateOnDuplicate` set, in postgres. The unique index may be a partial index. Closes sequelize#11534, sequelize#11569
@fnimick If |
Do we have an ETA on when this PR might get looked at? Or how we can get it merged in? Is there any work required on contributors end to get this pushed through? |
Fixed by #11984 |
Adds options `upsertKeys` and `upsertIndex`. This allows the use of a unique index for a `bulkCreate` with `updateOnDuplicate` set, in postgres. The unique index may be a partial index. Closes sequelize#11534, sequelize#11569
Adds options `upsertKeys` and `upsertIndex`. This allows the use of a unique index for a `bulkCreate` with `updateOnDuplicate` set, in postgres. The unique index may be a partial index. Closes sequelize#11534, sequelize#11569
Adds options `upsertKeys` and `upsertIndex`. This allows the use of a unique index for a `bulkCreate` with `updateOnDuplicate` set, in postgres. The unique index may be a partial index. Closes sequelize#11534, sequelize#11569
Adds options `upsertKeys` and `upsertIndex`. These options work with sqlite as well as postgres. This allows the use of a unique index for a `bulkCreate` with `updateOnDuplicate` set. The unique index may be a partial index. Closes sequelize#11534, sequelize#11569
Adds options `upsertKeys` and `upsertIndex`. These options work with sqlite as well as postgres. This allows the use of a unique index for a `bulkCreate` with `updateOnDuplicate` set. The unique index may be a partial index. Closes sequelize#11534, sequelize#11569
Adds options `upsertKeys` and `upsertIndex`. These options work with sqlite as well as postgres. This allows the use of a unique index for a `bulkCreate` with `updateOnDuplicate` set. The unique index may be a partial index. Closes sequelize#11534, sequelize#11569
Issue Description
What are you doing?
I am trying to use
bulkCreate
toupdateOnDuplicate
when a duplicate is detected. Duplicate should be detected by a "multi column unique index".What do you expect to happen?
See the expected assertions from my SSCCE:
I wanted a duplicate to be detected by the
unique_timestamp_per_foo
unique key when calling thebulkCreate
method withupdateOnDuplicate
array set.Furthermore, I wanted the insert SQL to be
ON CONFLICT ("timestamp", "FooId")
instead ofON CONFLICT ("id")
What is actually happening?
A
SequelizeUniqueConstraintError
is thrown because the expected multi-field index does not get added toupsertKeys
here (sequelize/lib/model.js
Line 2705 in 3517eb7
Environment
Issue Template Checklist
How does this problem relate to dialects?
Would you be willing to resolve this issue by submitting a Pull Request?
The text was updated successfully, but these errors were encountered: