2012-09-19 16 views
7

I Have uno schema in questo modo:schema di documento Mongoose e validazione

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._%+-][email protected][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 

Così che il mio employees dal vivo in una serie di employee documenti all'interno di un department

Ho diversi department documenti che hanno un numero di employee documenti memorizzati nell'array employees.

Ho quindi aggiunto un nuovo department ma non contiene employees. Se poi tento di aggiungere un altro department senza employees, Mongoose produce un Duplicate key error per il campo employee.email che è un campo obbligatorio. Il campo employee.email è obbligatorio e unico e deve essere.

C'è comunque intorno a questo?

risposta

6

Se si attiva la Mongoose registrazione di debug con l'CoffeeScript equivalente di mongoose.set('debug', true); si può vedere cosa sta succedendo:

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 } 

Incorporando la piena EmployeeSchema nel employees gamma di DepartmentSchema (e non solo un ObjectId riferimento ad esso), si finisce per creare indici univoci su entrambi employees.email e department.employees.email.

Così quando si crea un nuovo department senza dipendenti si sta "esaurendo" il caso di posta elettronica indefinito nell'indice department.employees.email per quanto riguarda l'unicità. Quindi quando provi a farlo una seconda volta che il valore univoco è già stato preso e ottieni il Duplicate key error.

La soluzione migliore per questo è probabilmente quella di cambiare DepartmentSchema.employees in un array di riferimentia dipendenti anziché a oggetti completi. Quindi l'indice rimane nella raccolta employees a cui appartiene e non stai duplicando i dati e creando opportunità per le incongruenze.

+0

Grazie Johhny, non ero a conoscenza del comando _debug_, che è utile sapere per il debugging futuro. Né sapevo che Mongoose stava creando 2 indici (in realtà quando ne chiesi solo uno.) Sapevo che avrei potuto creare 2 raccolte diverse e avere un _refer_ all'altro per mezzo di un 'ObjectId', ma poi sono tornato a un modello relazionale. Avendo usato RDMS per molti anni ho voluto utilizzare una struttura incorporata che sembra essere una buona misura per questo modello. Come compromesso, suppongo di poter fare riferimento a una raccolta _email-address_ all'interno dell'oggetto dipendente incorporato e creare un indice univoco. –

0

Sembra che non sia possibile creare un indice unico su un singolo campo di un documento secondario. Sebbene la funzione db.collection.ensureIndex nella shell di Mongo appaia come consentita, verifica il sottodocumento nel suo insieme per la sua unicità e non il singolo campo.

È possibile creare un indice su un singolo campo di un sub-documento, non è possibile renderlo unico.

+2

È possibile creare un indice univoco su un campo sub-documento, ma l'unicità viene applicata in tutta l'intera collezione e 'alcun valore' è considerato uno dei valori unici. Vedi la mia risposta. – JohnnyHK

1

Guarda anche questi riferimenti:

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

mongoDB/mongoose: unique if not null (in particolare la risposta di JohnnyHK)

Il corto di esso è che, poiché Mongo 1.8, è possibile definire quello che viene chiamato un indice sparse, che solo prende il controllo unico se il valore non è nullo.

Nel tuo caso, si vorrebbe:

@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._%+-][email protected][a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}\b/ }, 
    'departmentId': { type: @schema.ObjectId, required: true } 
    'enddate': String, 
    'active': { type: Boolean, default: true } 

Avviso il sparse: true aggiunto al vostro indice su attributo email di EmployeeSchema.

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

Problemi correlati