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 :)
});
5
  • 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 over to solve this problem. Commented Apr 11, 2019 at 19:47
  • 1
    Return the promise chain Commented Apr 11, 2019 at 19:49
  • But the final response is not the output from this function, Do I just create another promise inside it? Commented Apr 11, 2019 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 Commented Apr 11, 2019 at 19:53
  • The promise solution solved it, thank you so much! Commented Apr 11, 2019 at 20:29

2 Answers 2

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

Sign up to request clarification or add additional context in comments.

1 Comment

Your second suggestion, as Andy and charlietfl stated above, is what worked for me, thanks!
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;
}

1 Comment

This won't change the promise to run synchronously. The finally will run before the db operation completes

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.