1

I'm setting up an API for my server and I'm trying to update a value in a JSON consisted of country codes and numerical values. I loop through an array of JSON retrieved from my DB (MongoDB) and update the value, then after the loop is finished I'm trying to return the updated list.

The problem is that the return value is the original list, without the updates. I've verified that the update is happening inside the loop.

I'm quite new to JS, so I've tried switching between let and const, tried updating countryList directly (but as I read through some posts, I understood that js passes all arguments by value, and not by reference).

//shortened list, just for the example. The original has all country codes.
const countryList = JSON.parse('{"ZW": 0, "ZM": 0, "ZA": 0, "YT": 0, "YE": 0, "WS": 0, "WF": 0}'); 
let updateCountryList = () => {
    let temp = countryList;
    db.collection('tweets').find({'place': {$ne: null}}).forEach((item) =>{
        if (item.emoji_list.includes(emoji)) {
            temp[item["place"]["country_code"]] += 1;
            console.log(temp); //prints updated list
        }
    });
    console.log(temp); //prints original, empty list
    return temp
};

The expected output, given the JSON above, should look like: {"ZW": 5, "ZM": 896, "ZA": 466, "YT": 23, "YE": 0, "WS": 1, "WF": 0}

I should mention that this is a part of a promise and a longer process. However, this is the first thing that happens.

Edit: This is what solved it:

const countryList = JSON.parse('{"ZW": 0, "ZM": 0, "ZA": 0, "YT": 0);
let updateCountryList = () => {
    return new Promise(resolve1 => {
        let temp = countryList;
        db.collection('tweets').find({'place': {$ne: null}}).forEach((item) => {
            if (item.emoji_list.includes(emoji)) {
                temp[item["place"]["country_code"]] += 1;
            }
        }).then(() => {
            resolve1(temp)
        });

    });

};
updateCountryList().then(temp => {
    console.log(temp); // WORKS :)
});
mrpink121
  • 191
  • 1
  • 3
  • 13
  • 1
    The call to your db is asynchronous. That second `console.log` will be called well in advance of any db operations being completed. You should look [this question/answers](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) over to solve this problem. – Andy Apr 11 '19 at 19:47
  • 1
    Return the promise chain – charlietfl Apr 11 '19 at 19:49
  • But the final response is not the output from this function, Do I just create another promise inside it? – mrpink121 Apr 11 '19 at 19:50
  • 1
    No you would then do `updateCountryList ().then(data=> /* do something with data*/)`. Make sure to return `temp` in final then() inside the function – charlietfl Apr 11 '19 at 19:53
  • The promise solution solved it, thank you so much! – mrpink121 Apr 11 '19 at 20:29

2 Answers2

2

Because you're updating inside of another function, and JS is asynchronous, you're probably returning the unchanged data before it's really updated.

You could pass a callback:

const updateCountryList = (cb) => {
  db.collection('tweets').find({'place': {$ne: null}}).forEach((item) => {
    let temp = countryList
    if (item.emoji_list.includes(emoji)) {
      temp[item["place"]["country_code"]] += 1
    }
    cb(temp)
  })
}

Or if your Mongo client works with Promises, you could use async/await or return the updated list in a final .then

Zac Anger
  • 6,983
  • 2
  • 15
  • 42
0

I believe you should use a try finally approach, to get your json up to date by finalizing all changes.

Something like:

try {    
    const countryList = JSON.parse('{"ZW": 0, "ZM": 0, "ZA": 0, "YT": 0, "YE": 0, "WS": 0, "WF": 0}'); 
    db.collection('tweets').find({'place': {$ne: null}}).forEach((item) =>{
        if (item.emoji_list.includes(emoji)) {
            temp[item["place"]["country_code"]] += 1;
            console.log(temp); //prints updated list
        }
    });
} finally {
    console.log('FINALLY ', temp);
    return temp;
}
  • This won't change the promise to run synchronously. The `finally` will run before the db operation completes – charlietfl Apr 11 '19 at 19:55