Mongoose文档架构和验证

时间:2012-09-19 15:34:42

标签: mongodb mongoose

我有一个这样的架构:

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位于employee

内的department个文档数组中

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

然后我添加了新的department,但它不包含employees。如果我在没有department的情况下尝试添加其他employees,则Mongoose会为Duplicate key error字段生成employee.email,这是必填字段。 employee.email字段是必需且唯一的,它必须是。

无论如何围绕这个?

3 个答案:

答案 0 :(得分:6)

如果使用相当于mongoose.set('debug', true);的coffeescript启用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 employees数组DepartmentSchema中嵌入完整的ObjectId(而不仅仅是employees.email对它的引用),最终会在department.employees.email上创建唯一索引{1}}和department

因此,当您创建一个没有任何员工的新department.employees.email时,您正在“使用”Duplicate key error索引中未定义的电子邮件案例,这是唯一性。因此,当您尝试第二次执行此特定值时,您将获得DepartmentSchema.employees

最好的解决方法可能是将ObjectId更改为employees对员工的引用数组,而不是完整对象。然后索引保留在它所属的{{1}}集合中,并且您不会复制数据并创建不一致的机会。

答案 1 :(得分:1)

查看以下参考资料:

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

答案 2 :(得分:0)

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

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