2012-08-08 4 views
22

Ich versuche ein Benutzermodell zu erstellen, das einen eindeutigen Benutzernamen hat. Hier ist der Code für sie:Was mache ich falsch in dieser Mongoose einzigartigen Pre-Save-Validierung?

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); 

ich auch, wenn die Einzigartigkeit Werke zu sehen, die Prüfung:

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(); 
}); 

Problem ist, ist es nicht. Jedes Mal, wenn ich den Code ausführe, erhalte ich ein neues Objekt. Ich bin mir bewusst, dass es wahrscheinlich andere Möglichkeiten gibt, Einzigartigkeit zu gewährleisten, aber ich würde es gerne so machen. Sollte ich nicht anrufen done, nachdem ich das Ergebnis der findOne Methode behandeln? Rufe ich next falsch?

Antwort

28

verwenden parallel middleware (mit next und done Parameter), müssen Sie true als zweiten Parameter zu übergeben.

Darüber hinaus gibt es zwei Möglichkeiten:

Ihr self.invalidate Anruf "username" statt "user" werden verweisen sollte. Wenn das nicht hilft, können Sie die Dinge nicht explizit durch einen Fehler Objekt done vorbei, wenn Sie den Speichervorgang abbrechen wollen:

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

Es hat funktioniert, aber das Fehlerformat ist nicht das gleiche. Wenn Sie also eine API erstellen und auf das Format des Fehlerobjekts zählen, werden Sie wahrscheinlich Probleme mit diesem Ansatz haben. Ich habe den https://npmjs.org/package/mongoose-unique-validator getestet und es hat wie ein Zauber für mich funktioniert. Das Fehlerobjekt ist ziemlich gleich. –

+0

für mich, das hat nicht funktioniert, ich musste die Signatur der Funktion ändern, um nur ein Argument zu haben (nächste) und dann nächsten mit Fehler oder nächsten ohne Parameter entsprechend – Matus

+0

@Matus Es gibt zwei Arten von 'pre' [ Middleware] (http://mongoosejs.com/docs/middleware.html): parallel (mit den 'next' und' done' Parametern) und seriell (mit nur 'next'). – JohnnyHK

33

http://mongoosejs.com/docs/api.html#schematype_SchemaType-unique ist der Weg zu gehen. Es verwendet tatsächliche MongoDb-Indizes, um sicherzustellen, dass Ihr Feld eindeutig ist. Keine Notwendigkeit für .pre Middleware.

Viel Spaß!

+7

Ja, aber keine benutzerdefinierte Fehlermeldung .. Und es gibt keine Möglichkeit, einen Unterschied zwischen zwei verschiedenen einzigartigen Fehler auf dem gleichen Dokument zu machen. Siehe https://groups.google.com/d/msg/mongoose-orm/BX7kz0BwLjk/JWuvD_p4hYcJ –

+2

+1 für was @YvesM. sagte, und auch wie in Mongoose docs: "Hinweis: Verletzung der Einschränkung ** gibt einen E11000-Fehler von MongoDB ** beim Speichern, ** nicht ein Mongoose-Validierungsfehler **." – kuzyn

3

Haben Sie darüber nachgedacht mit einem asynchronen Validator fangen den Fehler?

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

Es gibt ein wirklich gutes Plugin für Mungo, das wirklich einfach zu installieren und zu verwenden ist. Die Dokumentation ist hervorragend und es hat für mich zum ersten Mal funktioniert.

Es gibt jedoch ein Problem beim erneuten Speichern.

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

+0

In der Regel gegen mehr Module in Projekte zu bringen, aber ich denke auch, dass dies ein Muss ist, wenn Sie eine Menge Validierung durchführen und es ziemlich viel keine Refactor zu integrieren braucht – kuzyn