jonnify·redis /redis-patterns/data-modeling/geospatial/geoadd-and-geosearch

R7.06.1 · Geospatial — dive

GEOADD and GEOSEARCH.

Store locations and query by radius using Valkey’s core GEO commands — longitude first, then latitude. The lon-before-lat order is the single most common source of a GEO bug.

Select a command below to see what it does. Then the radius-search visual shows which cities fall inside a 600 km ring around San Francisco.

The four primary GEO commands. Select one; the readout names what it does and its key argument order.
GEOADD lon lat name → ZSET score GEOSEARCH BYRADIUS/BOX nearest members GEOPOS retrieve stored [lon, lat] GEODIST distance between two members
readout · Select a command. The four commands cover adding, querying, retrieving, and measuring — the full add-and-search surface.
§1

Longitude first — the classic gotcha

geospatial.md.txt · Adding Locations
docs/redis-patterns/content/community/geospatial.md.txt · figure 17 — GEOADD argument orderfrozen
GEOADD locations -122.4194 37.7749 "san_francisco"  # lon FIRST, then lat
GEOADD locations  -73.9857 40.7484 "new_york"
GEOADD locations   -0.1276 51.5074 "london"

# multiple in one call
GEOADD locations -122.4194 37.7749 "san_francisco" -73.9857 40.7484 "new_york"

GEOADD takes longitude before latitude. This follows the GeoJSON specification ([lon, lat]), but reverses the everyday geographic convention (“37.7749°N, 122.4194°W”). Passing arguments in the wrong order silently stores every point in the wrong location — Valkey accepts the call without error.

The same order applies to FROMLONLAT in GEOSEARCH and to the coordinates returned by GEOPOS. State the convention once at the boundary and enforce it everywhere.

Calling GEOADD on an existing member name replaces its coordinates. The return value is the count of newly added members; an update returns 0.

Notes on ValkeyGEOADD is a core Valkey command — no module required. It stores coordinates as a 52-bit interleaved geohash integer used as the ZSET score; the maximum precision is approximately ±0.6 m. Cite: valkey.io/commands/geoadd.

The lon-before-lat argument order is consistent with GeoJSON but counterintuitive for anyone who writes latitudes first. One wrong argument silently maps a city to the wrong hemisphere. Name the order explicitly in every GEOADD call comment.

§2

GEOPOS, GEODIST, and GEOHASH

geospatial.md.txt · Retrieving Coordinates / Calculating Distance / Geohash

GEOPOS retrieves stored coordinates as [longitude, latitude]. The returned values may differ by a few microdegrees from the input because coordinates are stored as 52-bit geohash integers (precision ±0.6 m). Unknown members return nil.

GEODIST measures the great-circle distance between two stored members. Four unit options cover all common applications:

UnitCodeUse-case
metresmPrecision within a city block
kilometreskmStandard for most apps
milesmiUS-centric distance display
feetftIndoor / floor-level precision
GEOPOS  locations "san_francisco"
# → [[-122.41940..., 37.77490...]]   (lon-first, ±0.6 m from stored geohash)

GEODIST locations "san_francisco" "new_york" km   # → 4129.09
GEODIST locations "san_francisco" "london"   mi   # → 5367.21

GEOHASH locations "san_francisco"
# → ["9q8yy9mfry0"]   (the geohash string — 11 chars ≈ ±2.4 m)

GEOHASH returns the human-readable geohash string. Longer strings encode finer precision; the stored ZSET score is the same value decoded to a 52-bit integer. The string form is useful for debugging and for exporting coordinates to other geospatial systems.

GEOPOS is the inverse of GEOADD; GEODIST is the great-circle distance calculator; GEOHASH exposes the internal encoding as a human-readable string. All three are introspection over the ZSET that GEOADD builds.

§3

GEOSEARCH — origins, shapes, and output options

geospatial.md.txt · Searching by Radius / Search Options

GEOSEARCH supersedes the deprecated GEORADIUS and GEORADIUSBYMEMBER (removed from the recommended API since 6.2). Two origin forms:

  • FROMMEMBER name — centre the search on a stored member
  • FROMLONLAT lon lat — centre on arbitrary coordinates (lon first)

Two shape forms: BYRADIUS r unit (circle) and BYBOX w h unit (rectangle centred on the origin, width × height). The radius-and-box queries dive covers both shapes in depth.

# from a stored member, circle, results closest-first
GEOSEARCH locations FROMMEMBER "san_francisco" BYRADIUS 500 km ASC

# from arbitrary coords, with all output options
GEOSEARCH locations FROMLONLAT -122.4 37.8 BYRADIUS 50 km WITHCOORD WITHDIST COUNT 10 ASC

Output options shape the result. Any combination is valid:

OptionAdds to each result
WITHCOORDThe stored [lon, lat]
WITHDISTDistance from the origin in the search unit
WITHHASHThe raw 52-bit geohash integer
COUNT NStop after N results — combine with ASC for “nearest N”
ASC / DESCSort by distance ascending or descending

FROMLONLAT + BYRADIUS + COUNT N + ASC is the “find the N nearest” pattern. Add WITHDIST when the client needs to display the distance; omit it to keep the result set leaner when order is all that matters.

§4

Radius-search visual — which cities fall inside?

interactive · GEOSEARCH FROMLONLAT BYRADIUS

The diagram below shows San Francisco (the search origin, in red) and five cities. Adjust the radius slider; the ring grows or shrinks and cities inside the radius turn green — exactly what GEOSEARCH … FROMLONLAT -122.4 37.8 BYRADIUS <r> km ASC returns. Distances are great-circle values, computed from the stored coordinates above.

Radius search from San Francisco. The ring models GEOSEARCH locations FROMLONLAT -122.4 37.8 BYRADIUS <radius> km ASC. Cities inside the radius are the result set.
600 km
SF Los Angeles Portland Las Vegas Seattle Denver Approx. great-circle distances (km)
readout · Adjust the slider. Cities inside the ring appear in the GEOSEARCH result set.

The visual uses the same coordinate set as figure 17. The ring radius scales with the SVG viewBox — one pixel here represents roughly 12 km at this zoom. The actual GEOSEARCH command uses great-circle distance, which is what the distance values in the readout reflect.

A radius search returns every member within the circular region centred on the origin, sorted by distance. The COUNT option stops the scan early — useful when only the nearest N results matter and scanning the full set is unnecessary.

§5

Grounding — core Valkey, no consumer surface

geospatial.md.txt · figure 17 · figure 19
the pattern

GEOADD encodes (lon, lat) into a 52-bit interleaved geohash integer stored as a ZSET score; GEOSEARCH is a bounded range-scan over that score space. The lon-before-lat order is the external interface; the internal representation is a sorted integer.

its application (standalone)

The natural homes are a store locator (GEOADD restaurants … + GEOSEARCH … BYRADIUS 5 km) and a ride-share driver index (GEOADD drivers … updated on each GPS ping). codemojex has no location dimension — it is a location-agnostic Telegram emoji game.

GEO commands are core Valkey; the store-locator and ride-share patterns are the standard worked examples. codemojex ships no geo surface — players guess emoji, and nothing in the game is placed in space.

§6

References

sources · related

Sources

Related in this course