Mongoose 唯一如果不为空并且如果状态
Mongoose unique if not null and if state
我有一个这样的唯一索引
code: {
type: String,
index: {
unique: true,
partialFilterExpression: {
code: { $type: 'string' }
}
},
default: null
},
state: { type: Number, default: 0 },
但是state为2时(已存档)我想保留代码,但应该可以重用代码,所以state为2时不能唯一。
我有什么方法可以做到这一点吗?
使用索引无法做到这一点。即使您对 code
和 state
使用复合索引,仍然会有
的情况
新建文档
{
code: 'abc',
state: 0
}
归档文件
{
code: 'abc',
state: 2
}
现在,尽管您拥有相同的代码,但您将无法存档新文档或取消存档已存档的文档。
你可以这样做
const checkCode = await this.Model.findOne({code:'abc', active:0})
if(checkCode){
throw new Error('Code has to be unique')
}
else{
.....do something
}
这是可能的,尽管它是通过此处记录的变通方法实现的 https://jira.mongodb.org/browse/SERVER-25023。
在 MongoDB 4.7 中,您将能够对同一字段应用不同的索引选项,但现在您可以添加一个不存在的字段来分隔两个索引。
这是一个使用变通方法的示例。
(async () => {
const ItemSchema = mongoose.Schema({
code: {
type: String,
default: null
},
state: {
type: Number,
default: 0,
},
});
// Define a unique index for active items
ItemSchema.index({code: 1}, {
name: 'code_1_unique',
partialFilterExpression: {
$and: [
{code: {$type: 'string'}},
{state: {$eq: 0}}
]
},
unique: true
})
// Defined a non-unique index for non-active items
ItemSchema.index({code: 1, nonExistantField: 1}, {
name: 'code_1_nonunique',
partialFilterExpression: {
$and: [
{code: {$type: 'string'}},
{state: {$eq: 2}}
]
},
})
const Item = mongoose.model('Item', ItemSchema)
await mongoose.connect('mongodb://localhost:27017/so-unique-compound-indexes')
// Drop the collection for test to run correctly
await Item.deleteMany({})
// Successfully create an item
console.log('\nCreating a unique item')
const itemA = await Item.create({code: 'abc'});
// Throws error when trying to create with the same code
await Item.create({code: 'abc'})
.catch(err => {console.log('\nThrowing a duplicate error when creating with the same code')})
// Change the active code
console.log('\nChanging item state to 2')
itemA.state = 2;
await itemA.save();
// Successfully created a new doc with sama code
await Item.create({code: 'abc'})
.then(() => console.log('\nSuccessfully created a new doc with sama code'))
.catch(() => console.log('\nThrowing a duplicate error'));
// Throws error when trying to create with the same code
Item.create({code: 'abc'})
.catch(err => {console.log('\nThrowing a duplicate error when creating with the same code again')})
})();
我有一个这样的唯一索引
code: {
type: String,
index: {
unique: true,
partialFilterExpression: {
code: { $type: 'string' }
}
},
default: null
},
state: { type: Number, default: 0 },
但是state为2时(已存档)我想保留代码,但应该可以重用代码,所以state为2时不能唯一。 我有什么方法可以做到这一点吗?
使用索引无法做到这一点。即使您对 code
和 state
使用复合索引,仍然会有
新建文档
{
code: 'abc',
state: 0
}
归档文件
{
code: 'abc',
state: 2
}
现在,尽管您拥有相同的代码,但您将无法存档新文档或取消存档已存档的文档。
你可以这样做
const checkCode = await this.Model.findOne({code:'abc', active:0})
if(checkCode){
throw new Error('Code has to be unique')
}
else{
.....do something
}
这是可能的,尽管它是通过此处记录的变通方法实现的 https://jira.mongodb.org/browse/SERVER-25023。
在 MongoDB 4.7 中,您将能够对同一字段应用不同的索引选项,但现在您可以添加一个不存在的字段来分隔两个索引。
这是一个使用变通方法的示例。
(async () => {
const ItemSchema = mongoose.Schema({
code: {
type: String,
default: null
},
state: {
type: Number,
default: 0,
},
});
// Define a unique index for active items
ItemSchema.index({code: 1}, {
name: 'code_1_unique',
partialFilterExpression: {
$and: [
{code: {$type: 'string'}},
{state: {$eq: 0}}
]
},
unique: true
})
// Defined a non-unique index for non-active items
ItemSchema.index({code: 1, nonExistantField: 1}, {
name: 'code_1_nonunique',
partialFilterExpression: {
$and: [
{code: {$type: 'string'}},
{state: {$eq: 2}}
]
},
})
const Item = mongoose.model('Item', ItemSchema)
await mongoose.connect('mongodb://localhost:27017/so-unique-compound-indexes')
// Drop the collection for test to run correctly
await Item.deleteMany({})
// Successfully create an item
console.log('\nCreating a unique item')
const itemA = await Item.create({code: 'abc'});
// Throws error when trying to create with the same code
await Item.create({code: 'abc'})
.catch(err => {console.log('\nThrowing a duplicate error when creating with the same code')})
// Change the active code
console.log('\nChanging item state to 2')
itemA.state = 2;
await itemA.save();
// Successfully created a new doc with sama code
await Item.create({code: 'abc'})
.then(() => console.log('\nSuccessfully created a new doc with sama code'))
.catch(() => console.log('\nThrowing a duplicate error'));
// Throws error when trying to create with the same code
Item.create({code: 'abc'})
.catch(err => {console.log('\nThrowing a duplicate error when creating with the same code again')})
})();