Lance Pollard
Lance Pollard

Reputation: 79390

How to build a city/state/country autocomplete?

I am working with the countries, states, cities db on GitHub. I want to make it into an autocomplete that will return for you the <city>, <state>, <country>, or <state>, <country> or just <country>. How should I structure the data in the database roughly so I can accomplish this? Right now I have a table for each model, city referencing the state_id, state referencing the country_id, but it seems like it will be very complicated to query such a 3-table model with autocomplete efficiently.

Since this dataset is small, I can also put it all into memory (in addition to having the data be in the DB tables with IDs). This way when someone selects San Francisco, California, USA, it can save the 3 IDs associated with it for future lookup. But at the same time, by storing it all in memory, we could potentially do better at looking up arbitrary search strings? What is a good data structure for such a thing?

Say for example someone searches China. Well there are dozens of cities named China<...>, as well as a place like China, Mexico, and probably others. What should I do to make it so it returns the best or most common match? Probably start listing the countries first, then the states, then the cities.

Alternatively, I could have 3 inputs, one for country, one for state, one for city, and you just select your value. But I think it would be cool to be more sophisticated with it and do autocomplete based on anything you type.

All this boils down to one question: How should this generally be structured from a datastructure/query perspective?

Upvotes: 0

Views: 1989

Answers (1)

Aviv Ben Shahar
Aviv Ben Shahar

Reputation: 319

All you need is an array of all the possible countries for example, then:

const coutries = ['a', 'b', 'c']


const autoCompleteOptions = (search) => {
   return coutries.filter(c => {
     const country = c.toLowerCase()
     return country.includes(search.toLowerCase())
   })
}

Now, on the HTML, we can use it to get the optional fits (the react way):

<div class="list-container">
    {options.map(option =>{
        return (<option-component option={option}>
                </option-component>)
    })}
</div>

That will be your rendered list. style it so it will appear under your input.

All left to do is get the input value on each user type, and re-render the list just under the input.

Highly recommend you to show only 5 countries (limit it in the code), or add a scroller inside the list-container.

In angular it might be even nicer, using a pipe as the function that returns the fit array.

Upvotes: 1

Related Questions