Physician Finder
Context
Pharma client needed physician finder for their website. Your basic search-by-location, plot results on a map, switch to a list. Data came from a CSV of names and addresses, re-imported every night.
Front-end was the easy part.
What it does
- Search by zip, city/state, or free-form address (Google Places autocomplete)
- Results on a custom-styled map and in a synced list
- Click a marker — highlights the list item; click a list item — pans the map
- Both views read the same React state, no coordination layer
The problem
Every night the client's system dropped a fresh CSV on the server. Instruction: truncate the physicians table and re-import from scratch. As I was building it out (and testing), I realized this was going to be an expensive geocoding problem.
I tried to push back at first, maybe a CRUD interface to keep data stable and auditable. They said, "Unfortunately, we just have a sales guy who needs to upload a CSV somewhere.""
So:
- Most addresses haven't changed
- Some physicians share an office
- Some CSV rows look different but resolve to the same coordinates
I had to work around it and made a seeder which checks for existing geocodes.
The seeder
Split physician and location into two tables — one-to-many. Many physicians can share a location; geocode each location once.
For each CSV row:
- Hash address parts (street, city, state, postal) with MD5 for a stable location ID
- Hash name + address for the physician—catches duplicates at the same address
- If the location hash already exists, skip geocoding and attach the physician to that location
// Location hash — street + city + state + postal
$l_arr = [$street, $city, $state, $postal];
$l_hex = md5(implode('|', $l_arr));
// Physician hash — name + address (catches duplicate physicians at same address)
$p_arr = [$name] + $l_arr;
$p_hex = md5(implode('|', $p_arr));
$location_id = DB::table('locations')
->whereRaw("HEX(`location_hash`) = ?", [$l_hex])
->value('id');One more check before inserting a new location: does the geocoding API's formatted address already exist in the database? Catches typos and abbreviations (Rd / Road, East, NE) that still resolve to the same real-world address.
// Geocoding API returned a canonical address —
// check if we already have it before inserting a new location record.
$location_id = DB::table('locations')
->where('address', $address)
->value('id');Typical nightly cron run: fewer than 5% of records hit the geocoding API. The rest match an existing hash and pass through.
What I'd do differently
Nightly truncation was inherited, not designed. Diff-based import would have made most of the seeder unnecessary. Either way, works well within the constraint.
Bonus! Demo
Look ma, I built a map.
Production runs for a pharma client and isn't public. I rebuilt the same front end with ~20 bars in my neighborhood so there's something to click through.
Spoiler alert: It's not going to blow your mind.