0

I have been trying to store MongoDB field value as variable but I get the Promise {< pending >}. I always thought I knew how to make async requests but seems like I really don't.

exports.main = (req, res, next) => {

    const dt = Post.findOne({ active: true }, function(err, data) {

        if (err) throw err;

        return data;

    }).sort({ $natural: -1 }).exec().then(doc => {

        return(doc);

    });

    // Logs --> Promise { <pending> }
    console.log(dt); 

}
Jakob Valik
  • 41
  • 1
  • 6

3 Answers3

3

If you want to access query result you should work inside callback or .then of query:

exports.main = (req, res, next) => {

    let promise = Post.findOne({ active: true }).sort({ $natural: -1 }).exec();

    promise.then((doc) => {
         console.log(doc);
         res.send(doc); // send data if needed. I think this is express route handler
    })
    .catch((err) => {
       console.log(err);
       next();
    })
}
Max Sinev
  • 5,884
  • 2
  • 25
  • 35
2

This is a problem that is similar to this popular one.

All actions that rely on query result should be performed inside then:

Post.findOne({ active: true }).sort({ $natural: -1 }).exec().then(dt => {
    ...
});

findOne callback argument isn't necessary for promises.

async..await can be conventionally used for synchronous-like control flow:

exports.main = async (req, res, next) => {
    try {
        const dt = await Post.findOne({ active: true }).sort({ $natural: -1 }).exec();
        ...
        next(); // if necessary
    } catch (error) {
        next(error);
    }
}

As explained in this answer, since Express doesn't handle promises, all errors should be handled by a developer by wrapping entire async function body with try..catch.

Estus Flask
  • 206,104
  • 70
  • 425
  • 565
1

Mongoose exec() method gives you a fully-fledged promise and when you return a value in the then

...exec().then(doc => {

    return(doc); // <-- returns a pending promise

});

this returns a Promise in the pending status, like what you are getting currently.

There are a number of ways you can return the document. Using async/await, follow this pattern:

exports.main = async (req, res, next) => {  
    try {
        const data = await Post.findOne({ active: true }).sort({ $natural: -1 }).exec();
        console.log(data);

        res.status(200).send(data);
    } catch(err) {
        console.error(err);
        next();
    }
}

Using the callback function

exports.main = (req, res, next) => {
    Post.findOne({ active: true }).sort({ $natural: -1 }).exec((err, data) => {
        if (err) throw err;
        console.log(data);

        res.status(200).send(data);
    });
}

Using promises

exports.main = (req, res, next) => {
    Post.findOne({ active: true }).sort({ $natural: -1 }).exec().then(data => {
        console.log(data);
        res.status(200).send(data);
    }).catch(err => {
        console.error(err);
        next();
    });
}
chridam
  • 100,957
  • 23
  • 236
  • 235