1

I want to use Axios + nedb in a NodeJS Script to gather data from an API into a local file. This is what I done so far:

var axios = require('axios');
var Datastore = require('nedb');
const fs = require('fs');

db = new Datastore({ filename: './../smb_share/art.db', autoload: true });

function getArt(limit, offset) {
    var config = {
      method: 'get',
      url: 'http://IPADD/api/data/2:1/?limit=' + limit + '&offset=' + offset',
      headers: { 
        'Accept': 'application/simple+json', 
        'Content-Type': 'application/json', 
        'Authorization': 'Basic XYZ'
      }
    };

    axios(config)
      .then(function (response) {
          response.data.erpDataObjects.forEach(element => {
              var doc = { number:element.head.number,
                          desc:element.head.desc
              };
              db.insert(doc, function (err, newDoc) {
                if(err =! null){
                  console.log(err);
                }   
            });
          });  
      })
    .catch(function (error) {
        console.log(error);
    });  
}

getArt(1000,0)
getArt(1000,1000)

This works fine, as long I am not gathering more data from the API. I need to call my function "getArt(limit, offset)" round about 400 times, because I get about 400000 docs from the API. I tried to do this with intervalTimers, so start every 5min the function and ++offset with 1000 each time the interval event is fired... Yes, I know that's weird, but it was the only way which worked for me at the moment. But when the API server is on heavy load, it takes too long for one query and I exceed the limit of call which end up in a mess.

My Question: how do I keep things clear and fire the functions when the function before is ready? I tried a lot of async/await stuff, but all ended up in errors or all was fired at the same time. What I basically need is something like ...

getArt(10000,0)
.then
getArt(10000,10000)
.then
getArt(10000,20000)
.then
...

But with the nested function of axios I don't know how to handle this with a promise. Can someone give me a hint?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Matthias
  • 485
  • 7
  • 21

1 Answers1

2

Have you tried making getArt an async function and simply awaiting it?

async function getArt(limit, offset){...}

async function Name(){
  await getArt(10000, 1000); // wait to complete before moving on
  await getArt(10000, 2000); // only execute when above is done
}

Name();

By not assigning the result of await, you simply tell your program to wait for this function to complete prior to moving on to next one.

Side Note:

Why not make a for loop which increments the offset and calls the getArt function?

async function Name(){
  var limit = 10000;
  for(let offset = 0; offset < limit; offset += limit/10){
    await getArt(limit, offset);
  }
}

Name();

I haven't tested this, but see no reason why it should not work.

Additionally, (to follow good practice guidelines) you should wrap your await statements in a try-catch block to deal with errors like so:

try{
  await getArt(limit, offset);
}
catch(err){
  console.error(err);
}
lbragile
  • 7,549
  • 3
  • 27
  • 64
  • Thank you @lbragile, I think i tried the simple async await function, but it ran through all function calls without waiting for the previous one. Also thanks for the Side Note, what I wanted to do when the wait works. I will give it a try again tomorrow in production to see if I made a mistake in my experimental code. – Matthias Oct 28 '20 at 21:06
  • @Matthias, something isn't adding up here, if you did async/await like I mentioned then the function should "wait" for a response prior to moving on to the next line. Do you mind sharing your implementation? Are you sure you did **async** function getArt(limit, offest){...}? – lbragile Oct 28 '20 at 21:27
  • SyntaxError: await is only valid in async function – Matthias Oct 29 '20 at 06:40
  • 1
    @Matthias As I mentioned twice, you need to use `async function getArt(limit, offset){}` in order to use `await getArt(limit, offset)`. – lbragile Oct 29 '20 at 06:46
  • thanks for the hint, I chekced it twice and my function is: async function getArt(limit, offset) {...} thats one thing what confuses me. – Matthias Oct 29 '20 at 06:48
  • @Matthias, I see my apologies, misunderstood your comment. You actually need to make the call in an async function: `async function getArt(limit, offset){} async function Name(){ await getArt(limit, offset);}}` Then call `Name()`. That should fix it! – lbragile Oct 29 '20 at 06:55
  • @Matthias, edited my original answer to reflect this. Let me know if there are still issues – lbragile Oct 29 '20 at 07:01
  • Thank you, it seems to work. Just for my understanding.. when I put a "console.log('api called') on top of the function "async function getArt(limit, offset){}, shouldn't than appear step by step "api called"? now it's just running through and "api called" pops up 40 times immediatly. – Matthias Oct 29 '20 at 07:19
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/223800/discussion-between-lbragile-and-matthias). – lbragile Oct 29 '20 at 07:26