猫鼬:如何定义一个独特的字段组合?

时间:2013-04-17 13:43:34

标签: mongoose

如果我有这样的架构:

var person = new Schema({
  firstName:  String,
  lastName: String,
});

我想确保只有一个文档具有相同的firstName和lastName。

我该如何做到这一点?

6 个答案:

答案 0 :(得分:79)

您可以使用模式上的index调用来定义唯一的复合索引:

person.index({ firstName: 1, lastName: 1}, { unique: true });

答案 1 :(得分:4)

有趣的小事我最近才通过Mongoose实验发现。我有以下架构例如:

const ShapesSchema = new mongoose.Schema({
  name: { type: String, required: true },
  user: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }
})

ShapesSchema.index({ name: 1, user: 1 }, { unique: true })

mongoose.model('Shapes', ShapesSchema)

我们的想法是创建一个在nameuser上唯一的复合索引。这样,只要每个形状具有不同的名称,用户就可以创建任意数量的形状。并且逆转也应该是正确的 - 只要具有不同的用户,形状就可以具有相同的名称。对我来说,这样做并没有成功。

我注意到除_id上的索引外,还创建了其他三个索引条目。 nameusername_user各一个都设置为唯一。我对模式进行了修改,并将unique: false包含在我用于复合索引的每个字段中,然后突然全部按预期工作。我最终得到的是:

const ShapesSchema = new mongoose.Schema({
  name: { type: String, required: true, unique: false },
  user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', unique: false }
})

ShapesSchema.index({ name: 1, user: 1 }, { unique: true })

mongoose.model('Shapes', ShapesSchema)

查看作为结果创建的索引,我仍然可以看到三个索引 - nameusername_user。但不同的是,前两个不是唯一的,最后一个,即化合物。现在,每个用户使用多个不同形状的用例,或者具有不同用户的同名形状,就像冠军一样。

答案 2 :(得分:1)

这样定义您的架构


var person = new Schema({
firstName:  String,
lastName: String,
index: true,
unique: true, 

});


person.index({ firstName: 1, lastName: 1}, { unique: true });

答案 3 :(得分:0)

我没试过这个,但是使用一个独特的索引应该可以解决这个问题。

db.person.ensureIndex( { "firstname": 1, "lastname": 1 }, { unique: true } )

答案 4 :(得分:0)

const personSchema = new Schema({ firstName:  String, lastName: String });
const person = mongoose.model('recipients', personSchema);
person.createIndexes();

您可能需要摆脱集合中的所有重复项,或者以更快,更简单的方式进行操作:

  

编辑代码,删除集合,然后重新启动Mongo。

答案 5 :(得分:0)

您可以这样定义自己的架构。

const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const bcrypt = require("bcryptjs");

    const userSchema = new Schema({
      firstName: {
        trim: true,
        type: String,
        required: [true, "firstName is required!"],
        validate(value) {
          if (value.length < 2) {
            throw new Error("firstName is invalid!");
          }
        }
      },
      lastName: {
        trim: true,
        type: String,
        required: [true, "lastName is required!"],
        validate(value) {
          if (value.length < 2) {
            throw new Error("lastName is invalid!");
          }
        }
      },
      username: {
        unique: [true, "Username already available"],
        type: String,
        required: [true, "Username is required"],
        validate(value) {
          if (value.length < 10) {
            throw new Error("Username is invalid!");
          }
        }
      },
      mobile: {
        unique: [true, "Mobile Number alraedy available"],
        type: String,
        required: [true, "Mobile Number is required"],
        validate(value) {
          if (value.length !== 10) {
            throw new Error("Mobile Number is invalid!");
          }
        }
      },
      password: {
        type: String,
        required: [true, "Password is required"],
        validate(value) {
          if (value.length < 8) {
            throw new Error("Password is invalid!");
          }
        }
      },
      gender: {
        type: String
      },
      dob: {
        type: Date,
        default: Date.now()
      },
      address: {
        street: {
          type: String
        },
        city: {
          trim: true,
          type: String
        },
        pin: {
          trim: true,
          type: Number,
          validate(value) {
            if (!(value >= 100000 && value <= 999999)) {
              throw new Error("Pin is invalid!");
            }
          }
        }
      }
      date: { type: Date, default: Date.now }
    });