How to handle entry and storage of location info with Phoenix and Ecto?

In my app, when users need to enter a city, state/province and country I’d like to facilitate a better UX with autocomplete/suggestions.

The location data will be used for user profiles and posts, i.e. probably each will have fields like: city, state and country.

Users should be able to start typing some city name and select the one in the correct country and state/province (with the help of fuzzy autosuggest), and the app should infer and store the city, state, and country in separate (atomic) fields.

On the other hand when searching for posts by eg. country the autocomplete box should only suggest a list of countries (fuzzy).

We only need to support English language for these two use cases.

How would you suggest to implement such requirement in 2020 (maybe with liveview)?

What libraries you’ve worked with and/or can suggest?

Would it be simpler to use some client-side JS library an then somehow validate data on server (to avoid non-existent or misspelled names)?

Does it make sense to use some external API (we have no need to do complex geolocation operations involving lat/long)?

What do you think about having a dedicated “Locations” model (table) in DB and use it for relations (eg. has_many) with other models? I’m not sure about performance (eg. for auto-suggest) considering this lib has over 138k cities.

Any advice is much appreciated!

2 Likes

I’d go with LiveView if you can. Consider actually running the query only after certain amount of characters were typed in. I would not store the definition of cities/countries in the database - just keep it in memory. If you need to query the data by location, I’d suggest adding an index on a string column.

1 Like

Thanks!
What would be a more efficient way to store so much data in memory?
i.e. how about performance of querying and validating correctness (inclusion) before saving to DB?

eg. maybe using a Struct with nested keys like:

 %Location{ 
  region(eg. Africa): %{
    country(eg. Egypt): %{
      state_province: [ ... list of cities ]
    }
  } 
}

(not sure if this is the right way to go).

Seems like a pretty common need (in many apps a user or institution may have one or more physical addresses), yet I couldn’t find any published best practices for Elixir/Phoenix.

I don’t want to reinvent the wheel here, so pointers to any libs or articles are welcome!

Many apps have addresses, but I’m not sure how many of those try to validate those given the nature of actual valid addresses being super complex and a list of cities likely being outdated a month after an update.

I made @kip deal with that question for his tzworld library recently. You can have a look here: Tz_world / timezone_boundary_builder update

It’s a tradeoff for access time against space in memory (against space on disk, which you likely have enough of). He used an in memory cache in places to prefilter the list of possible matches completely in memory. Not sure if there’s something like that you could do / or need.

Another option would be using postgres and proper full text search or even elasticsearch. Fuzzy text search requires a lot of details and sometimes one is better of using an existing solution for a problem.

2 Likes

Thanks for the pointers!