Mongoose: Model.create Promise resolved although no document saved

Created on 1 Feb 2018  ·  3Comments  ·  Source: Automattic/mongoose

Hello everyone,

I'm using mongoose version 5.0.3 and node version 9.4.0. According to mongoose documentation model.create should return a promise which, I assume, is resolved as the document created is saved in the DB. However as shown by the code below it seems that the promise is resolved before the document is saved in the DB.

async function test(){

    let schema = new mongoose.Schema({a: String});

    let model = mongoose.model('test', schema);

    await model.remove({}).exec();

    await model.create({ a: 'test'}, 
       (err,result)=> {console.log('created');});

    await model.findOneAndUpdate(
        { a : 'test' } , 
        { a: 'newValue'}
    )
    .exec((err, result) => {
        console.log('update : '+result);
    });

    await model.find({a: 'test'},(err,result) => {
        console.log(result); 
    });

}

output in terminal : 
    update : null
    found :
    created

findOneAndUpdate do not find any document. In addition to that "created" is appearing at the end in the terminal, hence the callback of the create method is executed as if the await was not waiting for the async task 'create' to be done.

However by adding a promise which is resolved once the callback of create is triggered, as shown below, we obtain the expected result :

async function test(){

    let schema = new mongoose.Schema({a: String});

    let model = mongoose.model('test', schema);

    await model.remove({}).exec();

    await new Promise((resolve,reject) => {
        model.create({ a: 'test'}, 
       (err,result)=> {
            console.log('created');
            resolve();
        });
    });

    await model.findOneAndUpdate(
        { a : 'test' } , 
        { a: 'newValue'}
    )
    .exec((err, result) => {
        console.log('update : '+result);
    });

    await model.find({a: 'newValue'},(err,result) => {
        console.log('found : ' +result); 
    });

}

output in terminal: 
     created
     update : { _id: 5a735fbc1fe826233014d62d, a: 'test', __v: 0 }
     found : { _id: 5a735fbc1fe826233014d62d, a: 'newValue', __v: 0 }

Now we have the expected result.

All functions which operate on the DB do return a promise that if resolved indicates that the operation has been done, specifically Query. I assume that was also the case of model.create although it doesnt return a query object strictly speaking. I also wonder what the fulfilled returned promise means as it does not show that the doc was created in the DB. Perhaps I missed the whole point but I find it a bit ambiguous

Most helpful comment

I believe I remember reading in the 4.x docs that if you pass a callback to model.create it doesn't return a promise.

let x = model.create({ a: 'test' }, () => {})
  x.then(console.log(x)) //TypeError: Cannot read property 'then' of undefined

if you pull out the callback:

let x = model.create({ a: 'test' })
  x.then(console.log(x)) // Promise { <pending> }

the 5.x source for model.js bears this out calling utils.promiseOrCallback

All 3 comments

I believe I remember reading in the 4.x docs that if you pass a callback to model.create it doesn't return a promise.

let x = model.create({ a: 'test' }, () => {})
  x.then(console.log(x)) //TypeError: Cannot read property 'then' of undefined

if you pull out the callback:

let x = model.create({ a: 'test' })
  x.then(console.log(x)) // Promise { <pending> }

the 5.x source for model.js bears this out calling utils.promiseOrCallback

Yup, @lineus is correct, can I close out this issue @CodeurSauvage ?

@CodeurSauvage @lineus is correct, mongoose 5 does not return a promise if a callback is specified. Your script works if you replace:

    await model.create({ a: 'test'}, 
       (err,result)=> {console.log('created');});

With:

    await model.create({ a: 'test'}).then(result => console.log('created'));
Was this page helpful?
0 / 5 - 0 ratings