Skip to content

Fix/n plus one routes for stops#522

Merged
aaronbrethorst merged 2 commits intoOneBusAway:mainfrom
Adityatorgal17:fix/n-plus-one-routes-for-stops
Mar 1, 2026
Merged

Fix/n plus one routes for stops#522
aaronbrethorst merged 2 commits intoOneBusAway:mainfrom
Adityatorgal17:fix/n-plus-one-routes-for-stops

Conversation

@Adityatorgal17
Copy link
Contributor

Problem

Every call to trips-for-location triggered N+1 database queries inside buildStopList — one GetRouteIDsForStop query per stop in the bounding box.

With the stop limit capped at 100, this resulted in up to 101 queries just to build the stop list for a single API request.


Root Cause

buildStopList performed a per-stop database query instead of batching route lookups.

Fix

Replace the per-stop query loop with a single batch query:

GetRouteIDsForStops(stopIDs)

Then:

  • Build stopID → []combinedRouteID map in memory
  • Extract raw route IDs using utils.ExtractCodeID
  • Store raw IDs in presentRoutes

This eliminates N+1 queries and restores correct route references.


Changes

File Change
trips_for_location_handler.go Replaced buildStopList with batch implementation; removed dead processRouteIds
trips_for_location_handler_test.go Added TestTripsForLocationHandler_ReferencesContainStopsAndRoutes

Testing

Ran all required checks:

  • make fmt
  • make lint
  • make test

Closes

Fixes #304
Supersedes #305

Copy link
Member

@aaronbrethorst aaronbrethorst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aditya, this is a really clean fix. You've not only eliminated the N+1 query problem in buildStopList, but you've also fixed a subtle pre-existing bug in the process — the old processRouteIds was storing combined IDs (e.g. "40_100479") in presentRoutes, but collectAgenciesAndRoutes passes those to GetRoutesByIDs, which queries WHERE routes.id IN (?) against raw IDs (e.g. "100479"). The combined IDs would never match, so route references were silently empty. Your use of utils.ExtractCodeID to store the raw ID fixes that. Nicely done.

Critical Issues (0 found)

None.

Important Issues (0 found)

None.

Strengths

  • Eliminates up to 100 per-stop queries with a single batch GetRouteIDsForStops call
  • Fixes the pre-existing bug where presentRoutes held combined IDs that couldn't match GetRoutesByIDs's raw ID lookup
  • The checked type assertion (r.RouteID.(string) with , ok) is safer than the old unchecked panic-on-failure version
  • Good test that validates end-to-end data integrity — stops reference routes that actually appear in references.routes
  • Clear comment at trips_for_location_handler.go:522-525 explaining the raw vs combined ID distinction

Checklist

  • Tests pass
  • Lint clean
  • N+1 eliminated
  • Route references bug fixed
  • New test validates the fix

nice work, merging.

@aaronbrethorst aaronbrethorst merged commit ebdd18e into OneBusAway:main Mar 1, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix N+1 query in buildStopList — replace per-stop GetRouteIDsForStop with batch GetRoutesForStops

2 participants