How to Implement Location Search With GraphQL and Google
In this lesson, we'll address the gameplan we have in mind in how we want to conduct location-based searching in our app.
Get the project source code below, and follow along with the lesson material.
Download Project Source CodeTo set up the project on your local machine, please follow the directions provided in the README.md
file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.
This lesson preview is part of the TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL - Part Two course and can be unlocked immediately with a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL - Part Two with a single-time purchase.
[00:00 - 00:17] In this lesson, we're not going to be writing any code, but instead we'll talk about the game plan we have in mind in how we want to conduct location-based searching. The objective or the feature we want in our app is to have the capability to allow for location-based searches for listings.
[00:18 - 00:34] If a user was to search for a country, like Canada, all the listings in our application that are in Canada will be surfaced and shown in the listings page. If a user was to search for a city, like Toronto, all the listings in the city of Toronto will be surfaced and shown in the page.
[00:35 - 00:58] If a user was to search for an address, we're not going to show listings for this particular address, but instead we'll show listings for the city in which this address per tains to. So, as an example, if a user was to search for 33 University Avenue, which is an address located in downtown Toronto, we'll get the listings for the city of Toronto.
[00:59 - 01:08] The city is the smallest searchable unit for where we want to surface information. With that said, how do we facilitate this location-based searching?
[01:09 - 01:21] The listing documents, or in other words, the documents in the listings collection of our database have three fields that will be used to help with our searching. Country, Admin, and City.
[01:22 - 01:47] At this moment in time, our listings resolver function when run uses the find method from the node Mongo driver to get the cursor, or in other words, the collection of information that is to be returned from the find. We've mentioned this before, but if no filters or properties are defined within the query in the find method, Mongo will simply return everything in the collection.
[01:48 - 02:05] We know if we specify certain selection filters within this query, perhaps something like this and say country is Canada, Mongo will find all the documents that satisfy this filter. So, in this case, it would return all the documents from the listings collection where the country field is Canada.
[02:06 - 02:16] And this is to be the same for the other fields. If we specify a filter for the admin, like Ontario, as shown here, we'll get all the documents where admin is Ontario.
[02:17 - 02:34] If we specified a city filter like this, we'll get all the documents where the city is Toronto. And lastly, if we wanted to filter documents in a more controlled manner, we can say we want to find listings where the listing countries in Canada, admin is Ontario, and city is Toronto.
[02:35 - 02:49] So this will filter away any listing documents that are in Canada, but don't have an admin or province in Ontario. And it will further filter away listings that are in Canada and Ontario, but aren't in the city of Toronto.
[02:50 - 03:13] So now that we have the first half of the problem sort of understood, when it comes to finding the correct listings, we can simply apply the appropriate filters in our Mongo query. However, when a user is to provide an input, whether it's an address, a city, or just an administration, how can we get more focused geographic information for this particular search?
[03:14 - 03:25] This is where we're going to use Google's geocoding API, and we're going to ge ocode the search input. Or in other words, we'll convert the input provided to valid geographic information.
[03:26 - 03:44] Here's an example response that we can see in the Google geocoding documentation for an address input of 1600 amphitheater Parkway Mountain View, California. From the results returned, we get address components, which summarize the components of the address in question.
[03:45 - 03:55] And the types field within each component here indicates the type of the returned geographic result. So here we see the street number is 1600.
[03:56 - 04:13] The route is amphitheater Parkway. The administrative area one tells us the state that this is in California, and the administrative area two tells us the county, Santa Clara.
[04:14 - 04:27] And we also get the country and postal code. We also get information like the geometry, so latitude and longitude, and a formatted address, but our solution is mostly concerned with the address components above .
[04:28 - 04:44] So with that said, how will we map the appropriate address component types to the fields we have in our listing document? The geocoder often returns a large list of address components and will only want to access and use a few.
[04:45 - 04:55] The country address component from the geocoder is the most straightforward one . It doesn't have a different type label, and everything we're going to search for has to have a country.
[04:56 - 05:09] It's the highest order returned from the geocoder. So we'll simply map the value we get from the country type address component to the country field in our query.
[05:10 - 05:29] Administration Level 1 from the geocoder indicates the first level entity below country, and in the United States and Canada this maps to the states and provinces of these countries respectfully. So we'll simply map the administration level 1 type from the geocoder result to the admin field in our query.
[05:30 - 05:39] Last but not least is the city. This is a little more tricky since we've noticed the geocoder doesn't return an address component for a type labeled city.
[05:40 - 05:54] What it returns is often locality, which indicates an incorporated city or town political entity. However, what we've found is occasionally the locality address component isn't provided for results for a few different inputs.
[05:55 - 06:12] But what we've recognized is in these cases a postal town field, which is a grouping of geographic areas such as the locality, is often provided. So for the city, what we'll do is we'll check for the locality address component and if that exists from the API, we'll use that.
[06:13 - 06:26] If locality doesn't exist, we'll then check for the postal town value. And one thing to mention is that our query depends on the fact a country can be found from the geocoder.
[06:27 - 06:41] When a user searches for a certain location, we'll want to have to add a filter for at least the country field. If a country can't be found from the geocoder, it probably means the search was invalid and will throw an error instead.
[06:42 - 07:03] However, if for some reason or another, we're unable to find the admin or we're unable to find the city, but the country value from the geocoder was returned, we'll simply only add the country filter and make the query. This is a pseudo code implementation of one step we're going to do and we'll talk more about this when we begin to write the code.
[07:04 - 07:19] And lastly, it'll be pretty important for the user to know what was recognized from their search. The user searches Toronto will want to be explicit and tell them the city, the admin and the country that their search falls into.
[07:20 - 07:31] So we'll need to have this information be sent from the server to the client. Hopefully, this lesson was helpful in talking about the game plan of what we intend to do.
[07:32 - 07:46] As an additional resource, we'll provide a link in the lesson manuscript for the Google documentation that explains each of the different address types from the result of the geocoding API. In the next lesson, we'll implement the solution we've talked about here in our server.