Mongoose Compound Index Unique + Sparse

落花浮王杯 提交于 2021-02-08 08:16:44

问题


I want to create an index which ensures, that I don't have a duplicate serialNr within the combination of amanufacturer + art. But some items don't have a serialNr. These I don't want to check/index.

Code

mySchema.index({ serialNr: 1, art: 1 , manufacturer: 1, deleted: 1}, { unique: true, sparse: true)

I tried it also with adding a partial Filter: partialFilterExpression: { serialNr: {$ne:null} } to the index options.

Question

How can I index it that inserting: [{art: 'a', manufacturer:'a', deleted:null}, {art: 'a', manufacturer:'a', deleted:null}] passes

and

[{serialNr: '123', art: 'a', manufacturer:'a', deleted:null}, {serialNr: '123', art: 'a', manufacturer:'a', deleted:null}]fails

I'm not trying to save: [{serialNr: null, art: 'a', manufacturer:'a', deleted:null}, {serialNr: null, art: 'a', manufacturer:'a', deleted:null}]


The mongo docs state, that it should not be indexed if a field is missing in a compound index:

Sparse indexes selects documents to index solely based on the existence of the indexed field, or for compound indexes, the existence of the indexed fields. https://docs.mongodb.org/manual/core/index-partial/

EDIT:

New Index

implantSchema.index({ serialNr: 1, art: 1 , manufacturer: 1, deleted: 1}, { unique: true, partialFilterExpression: { serialNr: {$exists:true} }})

Before I make changes on the index I drop my collection in my dev-database, to ensure that there is no old index existing. This is the new index which is returned on db.items.getIndexes() /* 0 */ { "0" : { "v" : 1, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "LOC_db.items" }, "1" : { "v" : 1, "unique" : true, "key" : { "serialNr" : 1, "art" : 1, "manufacturer" : 1, "deleted" : 1 }, "name" : "serialNr_1_art_1_manufacturer_1_deleted_1", "ns" : "LOC_db.items", "partialFilterExpression" : { "serialNr" : { "$exists" : true } }, "background" : true } }

Data

  • I have a pre save hook where I check the value of serialNr, which does not exist before, the dup error is returned.
  • When querying the database there is no doc existing which has null, "" as value for the serialNr.
  • The query db.items.find({ serialNr: {$exists:true} }) does not match any items.

Error

insertDocument :: caused by :: 11000 E11000 duplicate key error index: LOC_db.items.$serialNr_1_art_1_manufacturer_1_deleted_1 dup key: { : null, : "Robo", : "Olymp", : null }

Additional Information

Maybe the error is related to: https://github.com/Automattic/mongoose/issues/2457


回答1:


You were actually quite close to the solution, all you need to use this when creating index :

partialFilterExpression: { serialNr: {$exists:true} }

Be sure to have at least 3.2 version of mongo


Example :

db.col.createIndex({a:1, b:1},{unique:true, partialFilterExpression: { a: {$exists:true} })
db.col.save({a:50, b:27}) //pass
db.col.save({a:50, b:27}) //fails
db.col.save({b:27}) //pass
db.col.save({b:27}) //pass
db.col.save({b:27}) //pass
db.col.save({a:50, b:27}) //fails
db.col.save({a:50}) //pass
db.col.save({a:50}) //fails

PS : Maybe you can do little "hack" and use this : partialFilterExpression: { serialNr: {$exists:true}, serialNr: {$gte:0} }

I tried using $ne, but it was throwing me an error.



来源:https://stackoverflow.com/questions/35920733/mongoose-compound-index-unique-sparse

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!