【问题标题】:Mongoose document schema and validationMongoose 文档架构和验证
【发布时间】:2012-09-11 22:58:20
【问题描述】:

我有这样的架构:

class Schemas

  constructor: ->
    @mongoose = require 'mongoose'
    @schema = @mongoose.Schema

    @EmployeeSchema = new @schema
      'firstname': { type: String, required: true }, 
      'lastname': { type: String, required: true }, 
      'email': { type: String, required: true, index: { unique: true }, validate: /\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}\b/ },
      'departmentId': { type: @schema.ObjectId, required: true }
      'enddate': String,
      'active': { type: Boolean, default: true } 

    @EmployeeSchemaModel = @mongoose.model 'employees', @EmployeeSchema

    @DepartmentSchema = new @schema
      'name': { type: String, required: true, index: { unique: true } }
      'employees' : [ @EmployeeSchema ]

    @DepartmentSchemaModel = @mongoose.model 'departments', @DepartmentSchema

这样我的employees 就存在于department 内的employee 文档数组中

我有几个department 文档,其中有多个employee 文档存储在employees 数组中。

然后我添加了一个新的department,但它不包含employees。如果我随后尝试添加另一个department 而没有employees,Mongoose 会为employee.email 字段生成一个Duplicate key error,这是一个必填字段。 employee.email 字段是必填且唯一的,而且必须如此。

这里面还有吗?

【问题讨论】:

    标签: mongodb mongoose


    【解决方案1】:

    如果您使用相当于 mongoose.set('debug', true); 的咖啡脚本启用 Mongoose 调试日志记录,您可以看到发生了什么:

    DEBUG: Mongoose: employees.ensureIndex({ email: 1 }) { safe: true, background: true, unique: true }      
    DEBUG: Mongoose: departments.ensureIndex({ name: 1 }) { safe: true, background: true, unique: true }      
    DEBUG: Mongoose: departments.ensureIndex({ 'employees.email': 1 }) { safe: true, background: true, unique: true }  
    

    通过将完整的EmployeeSchema 嵌入到DepartmentSchemaemployees 数组中(而不仅仅是一个ObjectId 引用),您最终会在employees.emaildepartment.employees.email 上创建唯一索引。

    因此,当您在没有任何员工的情况下创建一个新的 department 时,您将“用尽”department.employees.email 索引中未定义的电子邮件案例作为唯一性。因此,当您第二次尝试执行此操作时,该唯一值已被获取,您将获得 Duplicate key error

    解决此问题的最佳方法可能是将DepartmentSchema.employees 更改为ObjectId 对员工的引用而不是完整对象的数组。然后索引将保留在它所属的 employees 集合中,您不会复制数据并为不一致创造机会。

    【讨论】:

    • 谢谢 Johhny,我不知道 debug 命令,这对以后的调试很方便。我也不知道 Mongoose 正在创建 2 个索引(真的,当我只要求一个时。)我知道我可以创建 2 个不同的集合,并通过 ObjectId 让一个引用另一个,但后来我又回到了关系模型。使用 RDMS 多年后,我想使用一个似乎非常适合该模型的嵌入式结构。作为一种折衷方案,我想我可以从嵌入的员工对象中引用 email-address 集合并创建一个唯一索引。
    【解决方案2】:

    查看这些参考资料:

    http://docs.mongodb.org/manual/core/indexes/#sparse-indexes

    mongoDB/mongoose: unique if not null(特别是 JohnnyHK 的回答)

    简而言之,从 Mongo 1.8 开始,您可以定义所谓的 sparse 索引,它只会在值不为空时进行唯一检查。

    在你的情况下,你会想要:

    @EmployeeSchema = new @schema
      'firstname': { type: String, required: true }, 
      'lastname': { type: String, required: true }, 
      'email': { type: String, required: true, index: { unique: true, sparse: true }, validate: /\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}\b/ },
      'departmentId': { type: @schema.ObjectId, required: true }
      'enddate': String,
      'active': { type: Boolean, default: true }
    

    注意 sparse: true 添加到 EmployeeSchema 的电子邮件属性的索引中。

    https://gist.github.com/juanpaco/5124144

    【讨论】:

      【解决方案3】:

      您似乎无法在子文档的单个字段上创建唯一索引。虽然 Mongo shell 中的 db.collection.ensureIndex 函数似乎允许您这样做,但它作为一个整体测试子文档的唯一性,而不是单个字段。

      您可以在子文档的单个字段上创建索引,但不能使其唯一

      【讨论】:

      • 您可以在子文档字段上创建唯一索引,但在整个集合中强制执行唯一性,并且“无值”被视为唯一值之一。看我的回答。
      猜你喜欢
      • 1970-01-01
      • 2016-02-29
      • 1970-01-01
      • 2014-01-22
      • 1970-01-01
      • 2019-06-03
      • 2014-09-15
      • 2020-05-22
      • 2014-08-27
      相关资源
      最近更新 更多