0

[I will answer this question but feel free to add solutions or other problems that may occur]

Working on a nodejs project where we use q promises heavily and mongoose I have found some unintuitive hickups combining the two.

First one is that mongoose promise does not have .fail or .catch.

Another one is that Model.create returns a promise that calls the resolve function with mutliple arguments when resolved. If this goes through Q then Q will call the resolve with only the first argument.

Please feel free to add more problems that may occur; I will put how I solved these things in an answer.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
HMR
  • 37,593
  • 24
  • 91
  • 160

2 Answers2

3

You can simply use the Q function to cast Mongoose promises to "proper" Q ones - this works in fact with every thenable.

So just use

Q(someMongoosePromise) .then(…).catch(…);

Multiple arguments are a different problem. However, there is a very simple hack: convert them to an array and work with that.

Q(Model.create([doc1,doc2]).then(Array)) .spread(function(d1, d2){ … });

(This solution doesn't apply in case Model.create returns a promise for a single number)

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • What about mongoose ability to specify alternative promise libraries. `mongoose.Promise = require('q').Promise;` – Jaime Aug 02 '17 at 21:54
  • @Jaime Yes, that's a good idea. Not sure why I didn't mention it, maybe it wasn't supported by either Q or mongoose 2 years ago. – Bergi Aug 02 '17 at 22:09
0

Because mongoose promises do not have a .catch or .fail (Note that q will remove these from their library as well) you can not return a failing mongoose promise on a q stack that ends with either .catch or .fail without turning it into a q promise first. Here is how I did that (this has been answered elsewhere on stack as well):

function something(){
  return q()//make sure this function returns a promise instead of an unhandled error
  .then(function(){
    //do some stuff
  })
  .then(function(){
    return someMongoosePromise
    .then(function resolve(res){//make sure to return a q promise if this function is called in a stack that has 
     //.then.then.then(function(){return something();}).fail(...
        return q.resolve(res);
      },function reject(err){
        return q.reject(err);
      }
    );
  });
}

Second problem I encountered was that Model.create([doc1,doc2]) resolves the promise with multiple arguments but when going through q q only calls resolve with one argument:

q()
.then(function(){
  return Model.create([doc1,doc2]);
})
.then(function(docs){
  docs===doc1;//David Copperfield took doc2
});

the solution is about the same as the first one:

q()
.then(function(){
  return Model.create([doc1,doc2])
  .then(function(){//let mongoose resolve the promise
    var ret=[],i=arguments.length;
    while(--i>-1){
      ret.push(arguments[i];
    }
    return q.resolve(ret);
  });
})
.then(function(docs){
  docs===[doc1,doc2];
});
HMR
  • 37,593
  • 24
  • 91
  • 160
  • Your second solution [doesn't actually work](http://stackoverflow.com/q/23803743/1048572) – Bergi Mar 11 '15 at 11:26
  • @Bergi I'll have a look tomorrow, maybe copy paste error – HMR Mar 11 '15 at 11:50
  • Ooops, ignore that comment please. It just looked too much like the deferred antipattern, sorry. But you actually don't need to use `q.resolve` and `q.reject` there at all, just `return ret` would be enough. – Bergi Mar 11 '15 at 11:58