首页 > 解决方案 > 猫鼬如果不为空且如果状态是唯一的

问题描述

我有一个像这样的唯一索引

    code: {
        type: String,
        index: {
            unique: true,
            partialFilterExpression: {
                code: { $type: 'string' }
            }
        },
        default: null
    },
    state: { type: Number, default: 0 },

但是当状态为 2(已归档)时,我想保留代码,但它应该能够重用代码,因此如果状态为 2,它就不能是唯一的。有什么办法可以做到这一点吗?

标签: node.jsmongodbmongoosemongoose-schema

解决方案


这是可能的,尽管这是通过此处记录的解决方法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')})
})();

推荐阅读