javascriptjsongoogle-apigoogle-placesstringify

How can I download a single merged JSON file within a loop whilst using Google API and Javascript?


I have a script that is looping through an array of Google Place IDs and returns some of their Place Details. I’m then using JSON.Stringify to output the data in JSON format.

function initMap() {

 //====Array of Google Place IDs=====//
  
var placeid_list = [{
    "placeid": 'ChIJryijc9s0K4gRG9aU7SDTXdA',
  }, {
    "placeid": 'ChIJaZ6Hg4iAhYARxTsHnDFJ9zE',
  }, {
    "placeid": 'ChIJl64IQXrYzUwR8CVOTRf_h3o',
  }, {
    "placeid": 'ChIJBTMkuph-zkwR9oEF8Nv3Z0o',
  }, {
    "placeid": 'ChIJ4QbSBj8IzkwRGi0ILu03_VA',
  }, {
    "placeid": 'ChIJc2nSALkEdkgRkuoJJBfzkUI',
  }, {
    "placeid": 'ChIJmzrzi9Y0K4gRgXUc3sTY7RU',
  }];

  function setPlaces() {

    var json = placeid_list;

     //====Loop for Place IDs=====//

    for (var i = 0, length = json.length; i < length; i++) {
      var data = json[i];
      createPlace(data);
    }
  }
  function createPlace(data) {
    var service = new google.maps.places.PlacesService(document.getElementById("placeResults"));
    console.log(data);
    service.getDetails({
      placeId: data.placeid,
      fields: [
        "name",
        "formatted_address",
        "place_id",
        "geometry",
        "type",
        "formatted_phone_number",
        "rating",
        "reviews",
        "website",
        "url",
        "photos",
        "opening_hours",
        "price_level"],

    }, function (result, status) {
      if (status != google.maps.places.PlacesServiceStatus.OK) {
        alert(status);
        return;
      }
      placeResults(data, result);

    });
  }
  function placeResults(data, result) {

 //====Merge Data from each of looped Place IDs=====//

    const mergedObj = Object.assign(result);
    const jsonStr = JSON.stringify(mergedObj, 0, 2);
    const jsonFile = document.getElementById("placeResults").textContent += jsonStr;

    //====Output JSON data in JSON File=====//

    const a = document.createElement("a");
    a.href = URL.createObjectURL(new Blob([jsonFile], {
    type: "application/json"
    }));
    a.setAttribute("download", "data.json");
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);

    //====Output JSON data in text format=====//

    //document.getElementById("placeResults").textContent += jsonStr;

  }
  setPlaces();
}

window.initMap = initMap;

I’m trying to make it so that the combined JSON details for each place can be downloaded as a single file. Currently, the code above is generating 7 separate file downloads (the same amount of place IDs I have). Each of these files contains data for all of the Place IDs. But I only need 1 of these files.

I have been able to combine the data from each of the 7 place IDs and display it using the following:

const mergedObj = Object.assign(result);
const jsonStr = JSON.stringify(mergedObj, 0, 2);
const jsonFile = document.getElementById("placeResults").textContent += jsonStr;

//====Output JSON data in text format=====//
    
//document.getElementById("placeResults").textContent += jsonStr;

To generate a downloadable JSON file containing the place details, I'm using this:

const a = document.createElement("a");
    a.href = URL.createObjectURL(new Blob([jsonFile], {
    type: "application/json"
    }));
    a.setAttribute("download", "data.json");
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);

I'm hoping someone can help me in getting just 1 file to download when the script runs. Ideally, the process if to loop through all the place IDs, output their data in JSON format, merge it all, then download a single file containing everything.

Any help is very much appreciated.


Solution

  • You have asynchronous calls to the Google PlacesService(), where the responses come back in an unpredictable order and timing. In order to collect the responses you could either use promises, or a counter that keeps track of the calls and returns.

    Here is your code modified using a counter. The code is untested since I don't have all the details.

    Some notes:

    function initMap() {
    
     //====Array of Google Place IDs=====//
      var placeid_list = [
        { "placeid": 'ChIJryijc9s0K4gRG9aU7SDTXdA' },
        { "placeid": 'ChIJaZ6Hg4iAhYARxTsHnDFJ9zE' },
        { "placeid": 'ChIJl64IQXrYzUwR8CVOTRf_h3o' },
        { "placeid": 'ChIJBTMkuph-zkwR9oEF8Nv3Z0o' },
        { "placeid": 'ChIJ4QbSBj8IzkwRGi0ILu03_VA' },
        { "placeid": 'ChIJc2nSALkEdkgRkuoJJBfzkUI' },
        { "placeid": 'ChIJmzrzi9Y0K4gRgXUc3sTY7RU',}
      ];
    
      function setPlaces() {
        let resultArray = [];
        let callCount = 0;
        placeid_list.forEach(data => {
          callCount++;
          createPlace(data, function(result) {
            callCount--;
            if(result) {
              resultArray.push(result);
            }
            if(!callCount) {
              // all async calls done
              placeResults(resultArray);
            }
          });
        });
      }
    
      function createPlace(data, callback) {
        var service = new google.maps.places.PlacesService(document.getElementById("placeResults"));
        console.log(data);
        service.getDetails({
          placeId: data.placeid,
          fields: [ "name", "formatted_address", "place_id", "geometry", "type", "formatted_phone_number", "rating", "reviews", "website", "url", "photos", "opening_hours", "price_level" ],
        }, function (result, status) {
          if (status != google.maps.places.PlacesServiceStatus.OK) {
            alert(status);
            callback();
            return;
          }
          callback(result);
        });
      }
    
      function placeResults(resultArray) {
        const mergedObj = Object.assign(resultArray);
        const jsonStr = JSON.stringify(mergedObj, 0, 2);
        const jsonFile = document.getElementById("placeResults").textContent += jsonStr;
    
        //====Output JSON data in JSON File=====//
        const a = document.createElement("a");
        a.href = URL.createObjectURL(new Blob([jsonFile], {
          type: "application/json"
        }));
        a.setAttribute("download", "data.json");
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
      }
    
      setPlaces();
    }
    
    window.initMap = initMap;