Mongoose with Bluebird promisifyAll - saveAsync on model object results in an Array as the resolved promise value

12,674

Solution 1

Warning: This behavior changes as of bluebird 3 - in bluebird 3 the default code in the question will work unless a special argument will be passed to promisifyAll.


The signature of .save's callback is:

 function (err, product, numberAffected)

Since this does not abide to the node callback convention of returning one value, bluebird converts the multiple valued response into an array. The number represents the number of items effected (1 if the document was found and updated in the DB).

You can get syntactic sugar with .spread:

person.saveAsync()
.spread(function(savedPerson, numAffected) {
    //savedPerson will be the person
    //you may omit the second argument if you don't care about it
    console.log(JSON.stringify(savedPerson));
})
.catch(function(err) {
    console.log("There was an error");
})

Solution 2

Why not just using mongoose's built-in promise support?

const mongoose = require('mongoose')
const Promise = require('bluebird')

mongoose.Promise = Promise
mongoose.connect('mongodb://localhost:27017/<db>')

const UserModel = require('./models/user')
const user = await UserModel.findOne({})
// ..

Read more about it: http://mongoosejs.com/docs/promises.html

Share:
12,674

Related videos on Youtube

winston smith
Author by

winston smith

Updated on June 04, 2022

Comments

  • winston smith
    winston smith almost 2 years

    I'm using bluebird's promisifyAll with mongoose. When I call saveAsync (the promisified version of save) on a model object, the resolved value of the completed promise is an array with two elements. The first is my saved model object, the second is the integer 1. Not sure what's going on here. Below is example code to reproduce the issue.

    var mongoose = require("mongoose");
    
    var Promise = require("bluebird");
    
    
    Promise.promisifyAll(mongoose);
    
    
    var PersonSchema = mongoose.Schema({
        'name': String
    });
    
    var Person = mongoose.model('Person', PersonSchema);
    
    mongoose.connect('mongodb://localhost/testmongoose');
    
    
    var person = new Person({ name: "Joe Smith "});
    
    person.saveAsync()
    .then(function(savedPerson) {
        //savedPerson will be an array.  
        //The first element is the saved instance of person
        //The second element is the number 1
        console.log(JSON.stringify(savedPerson));
    })
    .catch(function(err) {
        console.log("There was an error");
    })
    

    The response I get is

    [{"__v":0,"name":"Joe Smith ","_id":"5412338e201a0e1af750cf6f"},1]
    

    I was expecting just the first item in that array, as the mongoose model save() method returns a single object.

    Any help would be greatly appreciated!

  • winston smith
    winston smith over 9 years
    D'oh! I should have just read the mongoose docs properly! Thanks!
  • Muhammad Umer
    Muhammad Umer about 9 years
    @winstonsmith i've never docs more useless than mongoose docs.
  • stevek-pro
    stevek-pro over 8 years
    they are certainly a bit abstract. go to mongooses gitter to ask the community in case you dont understand the docs fully.
  • robertklep
    robertklep over 8 years
    Because the question is more than a year old, at which point Mongoose didn't support promises.
  • rckd
    rckd over 8 years
    @robertklep I found that thread while searching for some details about mongoose promise support, so my answer should be useful for other ppl as well :-) The current accepted answer in fact is misleading.
  • robertklep
    robertklep over 8 years
    It's not misleading, it's outdated. Which happens with questions and answers that are old :-)
  • rckd
    rckd over 8 years
    @robertklep Yes, the question is stillt outdated, but the answer is not! :-)
  • robertklep
    robertklep over 8 years
    How is the answer misleading then?
  • rckd
    rckd over 8 years
    @robertklep i talked about the "accepted answer". it's misleading if you are looking for promise-support and don't yet know that mongoose already has a built-in support for that. Nevermind, I'm out :-)
  • charliebrownie
    charliebrownie about 8 years
    @rckd so basically by using Mongoose's built-in promise support mongoose.Promise = require('bluebird'); we wouldn't need using Bluebird's promisifyAll() on Mongoose, right?
  • rckd
    rckd about 8 years
    @charliebrownie yes :-)