2

Currently i'm having huge problem when working with async function. The first thing i'm trying to compare my deleteArray (that has the current data that needs to be in the collection) with the data in the collection.

 static async updateDocsInCollection(data) {
        let deleteArray= [];

        // Insert all data into array.
        data.forEach(async (elem) => {
            deleteArray.push(elem.serial);
        }

        MongoClient.connect('mongodb://' + config.database.host + ':' + config.database.port, { useNewUrlParser: true }, async function(err,db){
        if (err) throw err;

        // Get the current documents from "inventory" collection".
        await dbo.collection("inventory").find({}).toArray(function(err, res) {
                if (err) throw err;

                // Iterate through res array and see if res element exists in
                // deleteArray
                res.forEach((elem) =>{
                    if(!deleteArray.includes(elem.serial)){
                        // if it don't, push it.
                        deleteArray.push(elem)
                        console.log(elem.serial + " Pushed into array");
                    }

                });

            });

         // Iterate through deleteArray and delete it from collection.
         deleteArray.forEach((elem) =>{
               console.log(elem);
               dbo.collection("onlineplayerservice").findOneAndDelete({ 'serial': elem.serial});
            }); 

         // closing db-connection.
         db.close();
        });  

The problem is that the code does not run in the right order because I cannot iterate through deleteArray even though I see (according to console.log) that data is entered there.

Do you have any tips on how I can do to ensure that this function is synchronized?

Neil Lunn
  • 148,042
  • 36
  • 346
  • 317
krm1337
  • 21
  • 1
  • 3
  • 1
    Please also read [How to properly reuse connection to Mongodb across NodeJs application and modules](https://stackoverflow.com/q/24621940/2313887) as you never include database connection inside a commonly called function. Also note that whilst you were given a response correcting you on **JavaScript** semantics of asynchronous methods, the **MongoDB** parts are still all incorrect. You should mainly refer to the linked answers and that additional link for structure and usage. – Neil Lunn Mar 05 '19 at 19:50

1 Answers1

3

The problem is that you use an async function inside your first forEach(). This means you iterate thought your array with asynchronous functions returning Promises, so the code won't wait for the forEach to finish before going to the next statement.

Direct answer:

I don't see any reason why you have an async here so I would just remove it. But if you really need it, here is what you should do:

// Will wait for all lambda async function inside the forEach to finish
await Promise.all(data.forEach(async (elem) => {
   deleteArray.push(elem.serial);
}));

Tips and corrections:

As a tip, if all you need is to get the serial attribute of all your data elements, you should use Arrays.map like this:

let deleteArray = data.map(function(elem) { return elem.serial; });

Another thing, you should choose whether using callbacks or Promises with async / await, not both:

// Wrong
await dbo.collection("inventory").find({}).toArray(function(err, res) {});

// Good with promise and await
let res = await dbo.collection("inventory").find({}).toArray();

// Good with callback
dbo.collection("inventory").find({}).toArray(function(err, res) {});

Complete fixed sample code:

static async updateDocsInCollection(data) {
    // Insert all data into array.
    let deleteArray = data.map(function(elem) { return elem.serial; });

    const dbo = await MongoClient.connect('mongodb://' + config.database.host + ':' + config.database.port, { useNewUrlParser: true });

    // Get the current documents from "inventory" collection".
    const res = await dbo.collection("inventory").find({}).toArray();  
    // Iterate through res array and see if res element exists in deleteArray
    res.forEach((elem) =>{
        if(!deleteArray.includes(elem.serial)){
           // if it don't, push it.
           deleteArray.push(elem.serial) // You forgot the .serial here
           console.log(elem.serial + " Pushed into array");
        }
    });

     // Iterate through deleteArray and delete it from collection.
     // The deleteArray already contains serials, not data elements
     deleteArray.forEach((serial) =>{
          console.log(serial);
          dbo.collection("onlineplayerservice").findOneAndDelete({ 'serial': serial});
     }); 

     // closing db-connection.
     db.close();
});  
Kapcash
  • 6,377
  • 2
  • 18
  • 40
  • 1
    Hi Kapcash Thank you so much for your answer and tips on how to improve the code. I feel that I understand a bit more about whether to use Callbacks or Promises with async. Despite the changes, it doesn't seem to execute the code in the right order. Do I need to change something more in the dbo.collection (inventory) snippet so that it can finish off before deleteArray.forEach () runs at the end? – krm1337 Mar 05 '19 at 15:35
  • 1
    I added the full code fixed, please give it a try. I haven't tested the code so it might still contains compile errors or something. Anyway, here is the way you should you async / await. Consider enter your code in debug mode to see how it executes. – Kapcash Mar 05 '19 at 15:53