node.js - sails - sequelize v3
Cómo lidiar con la asincronización Método FindOrCreate para pasaporte y mangosta (4)
El módulo de autenticación ''Pasaporte'' requiere un método FindOrCreate para iniciar sesión. Estoy usando mangosta para salvar a mis usuarios con el siguiente esquema:
var UserSchema = new Schema({
firstname: String,
lastname: String,
email: String,
accounts: []
});
El conjunto de cuentas contiene objetos que representan cuentas de Facebook, como {provider: "facebook", uid: "someFacebookId"}
.
Mi estrategia de autenticación se ve así:
// Authentication Strategy
passport.use(new FacebookStrategy({
clientID: CONFIG.fb.appId,
clientSecret: CONFIG.fb.appSecret,
callbackURL: CONFIG.fb.callbackURL
},
function(accessToken, refreshToken, profile, done) {
// asynchronous verification, for effect...
process.nextTick(function () {
User.find({ ''accounts.uid'': profile.id, ''accounts.provider'': ''facebook'' }, function(err, olduser) {
if(olduser._id) {
console.log(''User: '' + olduser.firstname + '' '' + olduser.lastname + '' found and logged in!'');
done(null, olduser);
} else {
var newuser = new User();
var account = {provider: "facebook", uid: profile.id};
newuser.accounts.push(account);
newuser.firstname = profile.name.givenName;
newuser.lastname = profile.name.familyName;
newuser.email = "TBD...";
newuser.save(function(err) {
if(err) { throw err; }
console.log(''New user: '' + newuser.firstname + '' '' + newuser.lastname + '' created and logged in!'');
done(null, newuser);
});
}
});
});
}
));
Problema: Después de consultar mi base de datos ( User.find(...)
) la función de devolución de llamada se ejecuta inmediatamente sin esperar a que mi base de datos responda. Esto da como resultado un objeto olduser
indefinido. Así que estoy recibiendo una copia del mismo usuario en mi base de datos cada vez que este usuario intenta iniciar sesión.
¿Cómo manejo esta devolución de llamada asincrónica correctamente?
User.find
devuelve una matriz de documentos que coinciden con sus condiciones. En su caso, desea usar User.findOne
en User.findOne
lugar, y luego verificar if (olduser)...
para determinar si se encontró un documento coincidente.
process.nextTick(function () {
var query = User.findOne({ ''fbId'': profile.id });
query.exec(function (err, oldUser) {
console.log(oldUser);
if(oldUser) {
console.log(''User: '' + oldUser.name + '' found and logged in!'');
done(null, oldUser);
} else {
var newUser = new User();
newUser.fbId = profile.id;
newUser.name = profile.displayName;
newUser.email = profile.emails[0].value;
newUser.save(function(err) {
if(err) {throw err;}
console.log(''New user: '' + newUser.name + '' created and logged in!'');
done(null, newUser);
});
}
});
});
Odio la nitidez, pero los otros métodos mencionados aquí se rompen si dos usuarios intentan registrarse al mismo tiempo: antes de entrar en producción, querrá echarle un vistazo a las transacciones: http://www.mongodb.org/ display / DOCS / two-phase + commit
Hay una aplicación para eso: mongoose-findorcreate