Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

geocode - array position changes depending on google data set #14

Open
54Factory opened this issue Jun 23, 2017 · 13 comments
Open

geocode - array position changes depending on google data set #14

54Factory opened this issue Jun 23, 2017 · 13 comments

Comments

@54Factory
Copy link

54Factory commented Jun 23, 2017

Hi, great work on the geocode function. More of a question than issue....
I am a newb to coding and Graph.cool so hopefully you could help out.
When running that function the data in the array result may change positions...
For instance an address that has a "neighborhood" type will shift the "locality" to [3],
where as an address without a "neighborhood" type "locality" lives in the [2] position.
Using static data I reworked some things from other questions on SO....to return values by type.
My question is how would I implement the comparison function into your code?
Thanks in advance for any help on this!

function getMatchedTypes() {
  let i,
      j,
      types;
  let address_component = {}
  // Loop through the Geocoder result set. Note that the results
// array will change as this loop can self iterate.
  for (i = 0; i < address_components.length; i++) {

    address_component = address_components[i];

    types = address_component.types;

    for (j = 0; j < types.length; j++) {
      if (types[j] === 'street_number') {
        streetNumber = address_component.long_name;
      }
      if (types[j] === 'route') {
        street = address_component.long_name;
      }
      if (types[j] === 'neighborhood') {
        neighborhood = address_component.long_name;
      }
      if (types[j] === 'locality') {
        city = address_component.long_name;
      }
      if (types[j] === 'administrative_area_level_1') {
        state = address_component.long_name;
      }
      if (types[j] === 'administrative_area_level_2') {
        county = address_component.long_name;
      }
      if (types[j] === 'postal_code') {
        zip = address_component.long_name;
      }
      if (types[j] === 'postal_code_suffix') {
        zip = address_component.long_name;
      }
      break;
    }
    // console.log(address_component);

  }
  const geoLocation = {
    // The Lat/Lng values are defined from response "formatted address object" - uncomment live
    // lat: location.lat,
    // lng: location.lng,
    street: `${streetNumber} ${street}`,
    city,
    neighborhood,
    county,
    state,
    zip
  }
  console.log(geoLocation);

}


getMatchedTypes(address_components);
@marktani
Copy link
Contributor

My question is how would I implement the comparison function into your code?

You can pretty much run the same code, it's normal JS 🙂

@54Factory
Copy link
Author

54Factory commented Jun 23, 2017

I've tried but get the following....
And can't find in the logs?? Sorry to pester and the need for hand holding!
But, once I get it....I will assist others and post all snippets!

"code": 5000,
"message": "A function returned an unhandled error. Please check the logs for executionId 'cj49xg0wd1dyp0184zup9z7ct'",
"requestId": "cj49xg0wd1dyp0184zup9z7ct"

@54Factory
Copy link
Author

54Factory commented Jun 23, 2017

Here is the most current non-working I have....

require('isomorphic-fetch')

module.exports = function (event) {
  const baseUrl = 'https://maps.googleapis.com/maps/api/geocode/json'
  const apiKey = 'API KEY'

  // Here we're merging contents of three inputs – country, city and street.
  // You could also have this be just one freestyle address input

  // this RegEx replaces spaces with plus signs to fulfill the requirements of the Google geocode API
  const addressInput = [event.data.street, event.data.zip].join('+').replace(/\s/g, '+')
  const address = encodeURI(addressInput)

  // Let's create the url to call
  const apiUrl = `${baseUrl}?address=${address}&result_type=street_address&key${apiKey}`

  return fetch(apiUrl)
    .then((res) => res.json())
    .then((json) => {
      const location = json.results[0].geometry.location
      const addressComponents = json.results[0].address_components;
      let i,
          j,
          types;
      let address_component = {}
  	// Loop through the Geocoder result set. Note that the results
	// array will change as this loop can self iterate.
  for (i = 0; i < address_components.length; i++) {
    address_component = address_components[i];
    types = address_component.types;
    for (j = 0; j < types.length; j++) {
      if (types[j] === 'street_number') {
        streetNumber = address_component.long_name;
      }
      if (types[j] === 'route') {
        street = address_component.long_name;
      }
      if (types[j] === 'neighborhood') {
        neighborhood = address_component.long_name;
      }
      if (types[j] === 'locality') {
        city = address_component.long_name;
      }
      if (types[j] === 'administrative_area_level_1') {
        state = address_component.long_name;
      }
      if (types[j] === 'administrative_area_level_2') {
        county = address_component.long_name;
      }
      if (types[j] === 'postal_code') {
        zip = address_component.long_name;
      }
      if (types[j] === 'postal_code_suffix') {
        zip = address_component.long_name;
      }
      break;
    }
    // console.log(address_component);

  }
  const geoLocation = {
    // The Lat/Lng values are defined from response "formatted address object" - uncomment live
    lat: location.lat,
    lng: location.lng,
    street: `${streetNumber} ${street}`,
    city,
    neighborhood,
    county,
    state,
    zip
  }
  //console.log(geoLocation);

}

      // Let's merge the existing location data with Google response
      const eventData = Object.assign(event.data, geoLocation);
      return {data: eventData}
    })
    .catch(err => {
      console.log(err)

    })
}

@marktani
Copy link
Contributor

Could you additional post the mutation that you do to execute the function? Sorry for the delay, somehow I just saw your message right now 😞

@54Factory
Copy link
Author

54Factory commented Jun 26, 2017

I am not returning the last .then is what I believe.
The if statements can be changed to switch.
I am having a hard time with the logs so my debugging is non-existent...
Please keep I'm mind I am self-taught and have been at this only a few months!
I apologize in advance for not really knowing what is going on but I am truly committed to making this work and sharing my solutions with the community.

const addMutation = gql
mutation AddCustomerAndLocation($zip: String!, $state: String!, $city: String!, $street: String!, $locationName: String!, $customer: LocationcustomerCustomer){
  createLocation(zip: $zip, state: $state, city: $city, street: $street, locationName: $locationName, customer: $customer){
    id
    locationName
    street
    city
    state
    zip
    customer{
      id
      firstname
      lastname
      email
      phone
    }
  }
}
;

@54Factory
Copy link
Author

the whole project is here
https://github.com/54Factory/54project

@marktani
Copy link
Contributor

That's right, the missing logs is a problem we're looking into already, I'm sorry it's negatively affecting you. Thanks so much for helping out though!

Could you try this function instead? There indeed was a problem that you did not return in the last then statement:

require('isomorphic-fetch')

module.exports = function (event) {
  const baseUrl = 'https://maps.googleapis.com/maps/api/geocode/json'
  const apiKey = 'API KEY'

  // Here we're merging contents of three inputs – country, city and street.
  // You could also have this be just one freestyle address input

  // this RegEx replaces spaces with plus signs to fulfill the requirements of the Google geocode API
  const addressInput = [event.data.street, event.data.zip].join('+').replace(/\s/g, '+')
  const address = encodeURI(addressInput)

  // Let's create the url to call
  const apiUrl = `${baseUrl}?address=${address}&result_type=street_address&key${apiKey}`

  return fetch(apiUrl)
    .then((res) => res.json())
    .then((json) => {
      const location = json.results[0].geometry.location
      const addressComponents = json.results[0].address_components;
      let i,
          j,
          types;
      let address_component = {}
      // Loop through the Geocoder result set. Note that the results
      // array will change as this loop can self iterate.
      for (i = 0; i < address_components.length; i++) {
        address_component = address_components[i];
        types = address_component.types;
        for (j = 0; j < types.length; j++) {
          if (types[j] === 'street_number') {
            streetNumber = address_component.long_name;
          }
          if (types[j] === 'route') {
            street = address_component.long_name;
          }
          if (types[j] === 'neighborhood') {
            neighborhood = address_component.long_name;
          }
          if (types[j] === 'locality') {
            city = address_component.long_name;
          }
          if (types[j] === 'administrative_area_level_1') {
            state = address_component.long_name;
          }
          if (types[j] === 'administrative_area_level_2') {
            county = address_component.long_name;
          }
          if (types[j] === 'postal_code') {
            zip = address_component.long_name;
          }
          if (types[j] === 'postal_code_suffix') {
            zip = address_component.long_name;
          }
          break;
        }
      }
      const geoLocation = {
        // The Lat/Lng values are defined from response "formatted address object" - uncomment live
        lat: location.lat,
        lng: location.lng,
        street: `${streetNumber} ${street}`,
        city,
        neighborhood,
        county,
        state,
        zip
      }
      return geoLocation
    }).then((geoLocation) =>
        // Let's merge the existing location data with Google response
        const eventData = Object.assign(event.data, geoLocation);
        return {data: eventData}
    })
    .catch(err => {
      console.log(err)
    })
}

Also, for me being able to try for myself, I would need the variable values for the mutation you posted above as well 🙂


As a little meta information, formatting your code when posting it on GitHub is very helpful! You can use this syntax:

image

@marktani
Copy link
Contributor

Ah, and another idea that increases the "feedback loop" for testing this function - use the Playground to trigger it, instead of your app 🙂

@54Factory
Copy link
Author

Thanks for all the tips! I need them!
So that fails and this is the response...

Error
CODE
400
MESSAGE
Compilation failed: Block-scoped declarations (let, const, function, class) not yet supported outside strict mode
ERROR
Block-scoped declarations (let, const, function, class) not yet supported outside strict mode
SyntaxError: Block-scoped declarations (let, const, function, class) not yet supported outside strict mode
at Object.exports.runInThisContext (vm.js:53:16)
at WebtaskModule.compileWebtask (/data/sandbox/lib/module.js:91:32)
at Object.defaultJavascriptCompiler [as nodejsCompiler] (/data/sandbox/lib/compiler.js:124:30)
at module.exports.options.nodejsCompiler.fnCallback (/data/io/2bebdcda0af5491f85eb6ef218389da3/webtask.js:5:11)
at /data/sandbox/lib/compiler.js:230:17
at /data/sandbox/node_modules/async/dist/async.js:3830:24
at replenish (/data/sandbox/node_modules/async/dist/async.js:946:17)
at iterateeCallback (/data/sandbox/node_modules/async/dist/async.js:931:17)
at /data/sandbox/node_modules/async/dist/async.js:906:16
at /data/sandbox/node_modules/async/dist/async.js:3835:13
mutation testGoogleGeocoding {
  createLocation(
    street: "7 Foster Ave",
    city: "Havertown",
    state: "Pennsylvania",
    zip: "19083"
  ) {
    id
    street
    neighborhood
    city
    state
    zip
    lat
    lng
  }
}

@54Factory
Copy link
Author

54Factory commented Jun 26, 2017

Also, in my Location Schema I would like to save the lat and lng in the same format as the geocode response. Such as this....geoLocation instead of lat and lng

geoLocation: {
         lat: 39.9444071,
         lng: -75.1631718
}

@kbrandwijk
Copy link
Contributor

All variables inside the loop are undefined (streetnumber, street, etc.), or am I missing something?

@kbrandwijk
Copy link
Contributor

kbrandwijk commented Jul 19, 2017

I ran into this problem before, and I use this:

let geoResult = {}
addressComponents.forEach(e => e.types.forEach(t => Object.assign(geoResult, {[t]: e.long_name})))
})

That will create an object like this:

{ street_number: '1600',
  route: 'Amphitheatre Pkwy',
  locality: 'Mountain View',
  political: 'United States',
  administrative_area_level_2: 'Santa Clara County',
  administrative_area_level_1: 'California',
  country: 'United States',
  postal_code: '94043' }

That's a lot easier to work with!

@kbrandwijk
Copy link
Contributor

Also, in my Location Schema I would like to save the lat and lng in the same format as the geocode response. Such as this....geoLocation instead of lat and lng

Create a JSON field geoLocation on the Location Type. Remove create permissions from that field if you only want to make it available as a result field, not input field. Then set it event.data.geoLocation = { long: ..., lat: ... }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

3 participants