-1

I'm using node.js and npm's sqlite package and discord.js to make a discord bot.

I try to get a array back from a async function containing a sqlite request.

It seems like my sqlite request is also asynchronous cause I get the empty response before the request is executed. How do I have to form my request to get it executed first?

I already read this post: How do I return the response from an asynchronous call? but I still dont get it. It is not a duplicate cause the question in the link is about ajax and did not help me much. I hope that if I see it with my own code I'm able to understand it better.

This is what I'm having at the moment. I already tried it with callbacks without a result.

Promise approach:

This is my async function in dbHandler.js.

  var Promise = require("bluebird");

  getList: function(userID) {
     return new Promise(function(resolve, reject) {
        var array = [];
        sql.each(`SELECT * FROM table WHERE userID = ?`, userID, (err, row) => {
           if (err) {
           return console.error(err);
        } else {
           console.log("row: " + row + " element: " + row.username);
           array.push(row);
        }
    });

    array.forEach(function(element) {
       console.log("element: " + element.username);
    });

    console.log("array: " + array);
       resolve(array);
    });
  }

And this is my call in list.js.

  db.getList(uid)
  .then(function(v) {
      console.log("size: " + v.size);
  })
  .catch(function(v) {
      console.log("failed: " + v);
  });

In console I get this.

  array:
  size: undefined
  row: [object Object] element: user1
  row: [object Object] element: user2
  row: [object Object] element: user3

Callback approach:

dbHandler.js

 getList: function(userID, callback) {
     var array = [];

     sql.each(`SELECT * FROM warns WHERE userID = ?`, userID, (err, row) => {
        if (err) {
           return console.error(err);
        } else {
           array.push(row);
        }
     });

     if (array) {
        callback("", array);
     } else {
        callback("error", "");
     }
 },

list.js

 db.getList(uid, function (err, response) {
    if (err) {
       console.log(err);
    } else {
       console.log(response.size);
    }
 });

With the callback approach I only get undefined in console.

omnomnom
  • 190
  • 1
  • 12
  • which nodejs version are you using? – Nelson Owalo Jan 30 '18 at 14:06
  • You could try async/await. Much better – Nelson Owalo Jan 30 '18 at 14:06
  • According to your log, the response object isn't empty. It contains an object `[object Object]` – Nelson Owalo Jan 30 '18 at 14:08
  • I'm using v8.9.4. The [object Object] is logged from inside my async function and it's logged after the v.size from my call which is empty. This is exactly the problem I have. – omnomnom Jan 31 '18 at 07:18
  • can you convert the dumped `[object object]` to string and see inst contents? use `JSON.stringify(obj);` – Nelson Owalo Jan 31 '18 at 08:34
  • also, async/await is much better `try { let res = await db.getList(uid); console.log(JSON.stringify(obj));} catch (e){console.log(e)}` just make sure you add wrap `async` to your function before using `await` – Nelson Owalo Jan 31 '18 at 08:42
  • How your code know that the list is complete? It looks like the sqlite "complete" callback is omitted, but could be useful. See [.each() documentation](https://github.com/mapbox/node-sqlite3/wiki/API#databaseeachsql-param--callback-complete) – Paul Jan 31 '18 at 09:37
  • Also, database and filesystem coding in nodejs or other javascript creates the same asynchronous coding issues as ajax. It doesn't matter what kind of server or service is on the other end, if the code is set up to accept a callback or return a Promise *and return immediately with no data* then you need to move away from imperative programming and use event-driven programming instead. – Paul Jan 31 '18 at 09:41
  • @Paul thank you for the link to documentation. With the "complete" callback I get the v.size output after the logs from callback function in the sqlite statement. But sadly still with an empty/undefined array. – omnomnom Jan 31 '18 at 11:42

1 Answers1

0

since you get the following output:

row: [object Object] element: user1
row: [object Object] element: user2
row: [object Object] element: user3

I can only assume that you get results from the database, but accessing it is the issue. I'd suggest you try to dump the whole object and see it's structure before deciding on how to access it.

Below I have modified your code to dump a readable version of the object. Start from there and debug.

    getList: function(userID) {
         return new Promise(function(resolve, reject) {
            var array = [];
            sql.each(`SELECT * FROM table WHERE userID = ?`, userID, (err, row) => {
               if (err) {
               return console.error(err);
            } else {
               console.log(JSON.stringify(row)); //lets get the contents of the row object
               array.push(row); console.log(JSON.stringify(array)); //also, lets know what array contains after adding all the rows
            }
        });
Nelson Owalo
  • 2,324
  • 18
  • 37
  • Accessing data is not the problem. With your version it just logs the contents of the rows in a readable form. Please look at the part of my question where I posted the console output. I get back an empty array BEFORE the sql.each reads the rows. Its a problem with asynchronity. I just dont know how to resolve the promise that it gives me back the array after it got filled with array.push. – omnomnom Jan 31 '18 at 11:25
  • why not use `sql.all`? instead of retreiving one row at a time and adding them to an array – Nelson Owalo Jan 31 '18 at 11:40
  • Because it is not a function from the package I'm using. I already tried with sql.all but then this part of the code isn't getting executed. – omnomnom Jan 31 '18 at 11:46