async waterfall issue when querying the DB

650 views Asked by At

I'm build a set of object to be saved in mongoDB from a csv stream. For each csv row I need to verify before saving that the object or objects do not exists in MongoDB. The below code runs inside a GET route.

I have been trying to use async waterfall but it does not behave the way I expected.

Here is the code

    async.waterfall([
        function (callback) {

            console.log('in function 1');
        -->  Diagnosis.findOne({name: diagnosisName}, function (doc){
                console.log(JSON.stringify(doc))
            })
            callback(null);

        },
        function (callback) {

            console.log('in function2')
            callback(null)
        }],

    function(err, results) {
        console.log('finished!')
        res.send("complete");
    })

I would expect this to return the following

in function1

doc object in JSON

in function2

finished!

instead I get

in function 1

in function2

finished!

null

it runs as expected for as long as there is no findOne() call. What am I missing??

Much appreciated

2

There are 2 answers

0
Jason Cust On

findOne is an async function. You would need to move the callback inside this function to follow the order you expect.

async.waterfall([
    function(callback) {
      console.log('in function 1');
      Diagnosis.findOne({name: diagnosisName}, function(doc) {
        console.log(JSON.stringify(doc));
        callback(null);
      });

    },
    function(callback) {

      console.log('in function2');
      callback(null);
    }
  ],

  function(err, results) {
    console.log('finished!');
    res.send("complete");
  }
);

But why not use the internal promise (or another promise lib)?

console.log('in function 1');
// exec creates a new promise
Diagnosis.findOne({name: diagnosisName}).exec(function(doc) {
  console.log(JSON.stringify(doc));
  // resolve this with doc
  return doc;
}).then(function(doc) {
  console.log('in function2');
  // resolve this with doc
  return doc;
}).then(results) {
  // results here is just doc from the previous resolution
  console.log('finished!');
  res.send("complete");
});
1
alex On

In your first function:

    function (callback) {

        console.log('in function 1');
    -->  Diagnosis.findOne({name: diagnosisName}, function (doc){
            console.log(JSON.stringify(doc))
        })
        callback(null);

    },

Your callback is called after calling findOne which is asynchronous. You should just use your callback whenever findOne is done. Which means:

    function (callback) {

        console.log('in function 1');
    -->  Diagnosis.findOne({name: diagnosisName}, function (doc){
            console.log(JSON.stringify(doc))
            callback(null);
        })


    },

Or even better

    function (callback) {

        console.log('in function 1');
    -->  Diagnosis.findOne({name: diagnosisName}, callback);


    },
    function (callback, doc) {
        console.log(JSON.stringify(doc))
        callback(null);
    },