2012-08-08 5 views
22

Sto provando a creare un modello Utente, che ha un nome utente univoco. Ecco il codice per esso:Che cosa sto sbagliando in questa convalida unica pre-salvataggio Mongoose?

var mongoose = require("mongoose"); 

var Schema = mongoose.Schema; 

var UserSchema = new Schema({ 
    username: String, 
    password: String, 
}); 

UserSchema.virtual("password_confirmation").get(function() { 
    return this.pw_conf; 
}).set(function(value) { 
    this.pw_conf = value; 
}); 

UserSchema.path("username").required(true); 
UserSchema.path("password").required(true); 

UserSchema.pre("save",function(next, done) { 
    var self = this; 
    mongoose.models["User"].findOne({username : self.username},function(err, user) { 
     if(user) { 
      self.invalidate("user","username must be unique"); 
     } 
     done(); 
    }); 
    next(); 
}); 

UserSchema.pre("save",function(next) { 
    if(this.pw_conf !== this.password) { 
     next(new Error("Must specify the password confirmation")); 
    } 
    else { 
     next(); 
    } 
}); 

module.exports = mongoose.model("User",UserSchema); 

ero anche testando per vedere se le opere unicità:

var User = require("./users"), 
    mongoose = require("mongoose"); 
var u = new User(); 

mongoose.connect('mongodb://localhost/my_database'); 

u.username = "me"; 
u.password = "password"; 
u.password_confirmation = "password"; 
u.save(function(err) { 
    if(err) { 
     console.log(err); 
    } 
    mongoose.disconnect(); 
}); 

Il problema è che non. Ogni volta che eseguo il codice, ottengo un nuovo oggetto creato. Sono consapevole che probabilmente ci sono altri modi per garantire l'unicità, ma mi piacerebbe farlo in questo modo. Non dovrei chiamare done dopo aver gestito il risultato del metodo findOne? Sto chiamando next sbagliato?

risposta

28

Per utilizzare parallel middleware (con next e done parametri), è necessario passare true come secondo parametro.

Oltre a ciò, ci sono due possibilità:

tuo self.invalidate chiamata deve essere riferimento a "username" invece di "user". Se questo non risolvere il problema, si può fallire le cose in modo esplicito passando un oggetto errore per done se si vuole interrompere l'operazione di salvataggio:

UserSchema.pre("save", true, function(next, done) { 
    var self = this; 
    mongoose.models["User"].findOne({username: self.username}, function(err, user) { 
     if(err) { 
      done(err); 
     } else if(user) { 
      self.invalidate("username", "username must be unique"); 
      done(new Error("username must be unique")); 
     } else { 
      done(); 
     } 
    }); 
    next(); 
}); 
+1

Ha funzionato, ma il formato dell'errore non è lo stesso, quindi se stai costruendo un'API e contando sul formato dell'oggetto di errore probabilmente avrai problemi con questo approccio. Ho testato https://npmjs.org/package/mongoose-unique-validator e ha funzionato come un fascino per me. L'oggetto error è praticamente lo stesso. –

+0

per me, questo non ha funzionato, ho dovuto cambiare la firma della funzione di avere un solo argomento (successiva) e quindi chiamando il prossimo con l'errore o il prossimo senza parametri di conseguenza – Matus

+0

@Matus Ci sono due tipi di 'pre' [ middleware] (http://mongoosejs.com/docs/middleware.html): parallelo (con i parametri 'next',' done') e serial (con solo 'next'). – JohnnyHK

33

http://mongoosejs.com/docs/api.html#schematype_SchemaType-unique è la strada da percorrere. Usa gli attuali indici MongoDb per assicurarsi che il tuo campo sia unico. Non è necessario il middleware .pre.

Divertiti!

+7

Sì, ma nessun messaggio di errore personalizzato .. E non c'è modo di fare la differenza tra i 2 diversi errori unici sullo stesso documento. Vedere https://groups.google.com/d/msg/mongoose-orm/BX7kz0BwLjk/JWuvD_p4hYcJ –

+2

+1 per quello @YvesM. detto, e anche come da documenti Mongoose: "NOTA: la violazione del vincolo ** restituisce un errore E11000 da MongoDB ** durante il salvataggio, ** non un errore di convalida di Mongoose **." – kuzyn

3

Hai pensato di usare un validatore asincrono per catturare l'errore?

UserSchema.path('username').validate(function (value, done) { 
    User.count({ username: value }, function (error, count) { 
    // Return false if an error is thrown or count > 0 
    done(!(error || count)); 
    }); 
}, 'unique'); 
5

C'è un ottimo plugin per mangusta che è davvero facile da installare e utilizzare. La documentazione è eccellente e ha funzionato per me la prima volta.

ma c'è un problema con il ri-risparmio.

https://npmjs.org/package/mongoose-unique-validator

+0

Di solito contro l'aggiunta di più moduli nei progetti, ma penso anche che questo è un must se hai intenzione di fare un sacco di convalida e praticamente non richiede alcun refactoring per integrare – kuzyn

Problemi correlati