2014-11-23 4 views
4

Я ищу совет о том, как связывать обещания «найти или создать» с помощью mongodb/mongoose.Mongoose - chaining promises

В настоящее время я пробовал:

userSchema.statics.findByFacebookIdOrCreate = function (facebookId, name, email) { 
    var self = this; 
    return this.findOne({facebookId: facebookId }).exec() 
    .then(function (user) { 
     if (!user) { 
     return self.model.create({ facebookId: facebookId, name: name, email: email }).exec().then(function (user) { 
      return user; 
     }); 
     } 
     return user; 
    }); 
}; 

И я называю это из моего (узел/экспресс) API конечной точки:

User.model.findByFacebookIdOrCreate(fbRes.id, fbRes.name, fbRes.email).then(function (user) { 
    return res.sendStatus(200).send(createTokenForUser(user)); 
    }, function (err) { 
    return res.sendStatus(500).send({ error: err }); 
    }); 

Проблемы, хотя:

  1. Несмотря на то, пользователь имеет значение null из запроса findOne, создание никогда не называется
  2. I'm n ВЗ, что я буду использовать правильный стиль Обещания/наиболее эффективный стиль кодирования
  3. ли я обработку ошибок правильно, например, только на верхнем уровне или сделать мне нужно сделать это на каждом уровне

Может кто-нибудь увидеть, что я «Я делаю неправильно, и как я мог бы сделать это лучше?

Спасибо.

UPDATE

Причина проблемы заключалась в том, что

self.model.create(...) 

должно быть (модель не ссылка)

self.create(...) 

Однако, теперь мне нужно знать, что я я ошибаюсь в обработке ошибок - я мог видеть, что произошла ошибка, но я не мог понять причину.

Я до сих пор есть некоторые ошибки, возникающие, которые я знаю, потому что я получаю статус 500

return res.sendStatus(500).send({ error: err }); 

но фактическое сообщение об ошибке/деталь пуста.

+0

1. Попробуйте 'return self.model.create (...' 2. При сборе обещаний всегда возвращайте либо новое обещание, либо окончательное значение. 3. Наличие единственной функции ошибки в конце просто отлично – Ivancho

+0

Спасибо, я действительно получил это возвращение, но это не помогло. Только вытащил его, чтобы увидеть эффект. – prule

+0

Я отредактировал вопрос, чтобы вернуть обратно. Любые другие идеи? – prule

ответ

2

Проблема может быть, что:

  1. создать метод возвращает обещание и doens't имеете метод Exec
  2. Если вы хотите использовать затем() в пользовательском методе вам придется возвратить обещание, но вы возвращаете мангустский документ: return user;

Это всегда возвращает обещание, это позволяет использовать затем() после вашего метода (Вы должны добавить mpromise модуля):

userSchema.statics.findByFacebookIdOrCreate = function (facebookId, name, email) { 
    var self = this; 
    var Promise = require('mpromise'); 
    var promise = new Promise; 
    this.findOne({facebookId: facebookId }).exec() 
    .then(function (user) { 
     if(user) { 
      promise.fulfill(user); 
      return; 
     } 

     self.model.create({ facebookId: facebookId, name: name, email: email }) 
      .then(function (user) { 
       promise.fulfill(user); 
       return; 
      }); 
    }); 
    return promise; 
}; 

Надеется, что это помогает

+0

Это очень похоже на [отложенный антипаттерн] (http://stackoverflow.com/q/23803743/1048572) – Bergi

0

Ваш вопрос (и последующий ответ от @ EduardoRodríguez) помог мне решить подобную проблему, так что ура!Однако, используя последнюю версию мангуста + деструктурирующие стрелками и функции ES6, я был в состоянии получить его на что-то похожее на следующее:

userSchema.statics.findByFacebookIdOrCreate = function (facebookId, name, email) { 
    var User = this; 
    return User.findOne({facebookId}) 
    .then(user => user || User.create({facebookId, name, email})); 
}; 

... а потом:

User.findByFacebookIdOrCreate(fbRes.id, fbRes.name, fbRes.email) 
    .then(user => res.sendStatus(200).send(createTokenForUser(user)) 
    .catch(error => res.sendStatus(500).send({error}); 

Примечание: это действительно связаны с использованием собственных обещаний ES6 путем настройки мангуста с:

mongoose.Promise = global.Promise; 

Я еще совсем новичок в этом, но, надеюсь, это поможет другим идти вперед (это работает для меня).