Home Do something after multiple async mongoose calls finishes
Reply: 1

Do something after multiple async mongoose calls finishes

Rasmus Puls
1#
Rasmus Puls Published in 2018-02-13 15:06:27Z

I have a function that looks up data in several different documents, add some of the date from each document to a object and returns the object with the combines data from the different documents. The only problem is that the object is returned before any of the transactions are completed. I have googled a lot, and the only solution i can find is on Stack Overflow, but from 2012.... There must be some "newer" better way to do it? Preferably without installing more npm stuff.

Here is my function

function getPreviousEventCard(event, callback) {
    const card = {};
    card.dateStart = event.dateStart;
    card.dateEnd = event.dateEnd;
    card.userID = event.userID;
    card.adminID = event.adminID;

    // 1st async call
    Profile.getFullName(event.userID, (err, name) => {
        if (err) return callback(err, null);
        card.bsName = name.fullName;
    });

    // 2nd async call
    Profile.getProfileByUserId(event.parentID, (err, profile) => {
        if (err) return callback(err, null);
        card.parentName = profile.fullName;
        card.address = `${profile.address} ${profile.zip}`
    });

    // somehow wait until both(all) async calls are done and then:
    return callback(null, card);
}

btw, 'Profile' is a mongoose schema, and the get methods are using the findOne() method.

I have tried to nest the functions and have the return callback as the most inner, but then it is never returned for some reason.

T.J. Crowder
2#
T.J. Crowder Reply to 2018-02-13 15:22:31Z

If you're using NodeJS v8 or higher, I would promisify those functions:

const getFullName = promisify(Profile.getFullName);
const getProfileByUserId = promisify(Profile.getProfileByUserId);

...and then use Promise.all:

function getPreviousEventCard(event, callback) {
    Promise.all([
        // 1st async call
        getFullName(event.userID),
        // 2nd async call
        getProfileByUserId(event.parentID)
     ])
    .then(([name, profile]) => {
        const card = {
            dateStart: event.dateStart,
            dateEnd: event.dateEnd,
            userID: event.userID,
            adminID: event.adminID,
            bsName: name.fullName,
            parentName: profile.fullName,
            address: `${profile.address} ${profile.zip}`;
        };
        callback(null, card);
    })
    .catch(err => callback(err);
}

or better yet, make getPreviousEventCard return a promise:

function getPreviousEventCard(event) {
    return Promise.all([
        // 1st async call
        getFullName(event.userID),
        // 2nd async call
        getProfileByUserId(event.parentID)
     ])
    .then(([name, profile]) => {
        return {
            dateStart: event.dateStart,
            dateEnd: event.dateEnd,
            userID: event.userID,
            adminID: event.adminID,
            bsName: name.fullName,
            parentName: profile.fullName,
            address: `${profile.address} ${profile.zip}`;
        };
    });
}

Preferably without installing more npm stuff

If you did want to install more npm stuff, there's an npm module that will promisify an entire API (rather than function by function) using a declarative description of the APIs functions: https://www.npmjs.com/package/promisify

You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.319695 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO