R7.06.2 · dive 2
Radius and box queries.
GEOSEARCH answers “what is near here?” in two shapes: a circle
(BYRADIUS) or a rectangle (BYBOX). Toggle the shape; the same reference
point returns different member sets.
A circle clips the corners; a rectangle extends into them. Toggle above to see the difference.
The second interactive walks the two-step pattern: GEOSEARCH finds nearby ids, then
HGETALL fetches each record from its companion Hash.
BYRADIUS searches a circle; BYBOX searches a rectangle width × height centred
on the reference point. Same origin, different result sets at the corners.Circle vs rectangle — BYRADIUS and BYBOX
geospatial.md.txt · Searching by Radius / Searching by Bounding BoxGEOSEARCH takes a shape argument that controls the area. Both shapes are centred
on the reference point, which may be a stored member (FROMMEMBER) or explicit coordinates
(FROMLONLAT):
GEOSEARCH locations FROMLONLAT -122.4 37.8 BYRADIUS 50 km COUNT 10 ASC GEOSEARCH locations FROMLONLAT -122.4 37.8 BYBOX 100 80 km COUNT 10 ASC # key from-lon from-lat shape opts # BYBOX takes width × height — the box is centred on the reference point
A circle with radius 50 km and a box 100 km wide by 80 km tall both contain many of the same members, but
differ at the corners: the circle clips them; the box includes them. A delivery zone or a map-tile bounding
box is a natural fit for BYBOX; a “restaurants within N km” query is a natural fit
for BYRADIUS.
Output options on both shapes:
WITHCOORD— include stored coordinates.WITHDIST— include the distance from the reference point.WITHHASH— include the raw geohash integer (the ZSET score).COUNT N— return at most N results.ASC/DESC— sort by distance, closest or furthest first.
BYRADIUS draws a circle; BYBOX draws a rectangle. The choice is domain-driven:
a delivery zone is a rectangle; a proximity search is a circle. Both accept the same output modifiers.
GEOSEARCHSTORE — persisting results
geospatial.md.txt · Storing Search ResultsGEOSEARCHSTORE runs a spatial query and writes the result set to a new key as a
Sorted Set. Because a GEO set is a Sorted Set (that is the subject of the next dive), the output can be consumed
with ZRANGE, ZCARD, or ZREM like any other Sorted Set:
GEOSEARCHSTORE nearby_cache locations FROMLONLAT -122.4 37.8 BYRADIUS 50 km # dest-key src-key from-coords shape # Result stored as a Sorted Set with geohash scores at nearby_cache
Use GEOSEARCHSTORE when the same spatial query is repeated frequently: run it once, cache the
Sorted Set, and serve repeated reads from the cached key. The output is re-queryable with any ZSET command,
including a second GEOSEARCH over the stored result.
Notes on ValkeyGEOSEARCH and GEOSEARCHSTORE
are core Valkey commands (available since Redis 6.2 / Valkey 9, no module required). They
supersede the older GEORADIUS / GEORADIUSBYMEMBER forms, which are deprecated and
should not appear in new code. See
valkey.io/commands/geosearch ·
valkey.io/commands/geosearchstore.
GEOSEARCHSTORE materialises a spatial query as a reusable Sorted Set. Because the
output is a ZSET, all downstream ZSET commands apply without any conversion.
Location with metadata — the separate-Hash pattern
geospatial.md.txt · Location with MetadataA GEO member carries only a name. The Sorted Set score is the geohash integer; there is no room for additional fields. The pattern for attaching metadata:
- Add a named id as the GEO member — the name is the join key.
- Store all metadata in a Hash under that id.
- Search returns ids; then fetch each Hash.
# Step 1: add the id as the GEO member GEOADD restaurants -122.4194 37.7749 "restaurant:123" # Step 2: store metadata in a companion Hash HSET restaurant:123 name "Joe's Diner" cuisine "American" rating "4.5" # Step 3: search returns ids; fetch each row GEOSEARCH restaurants FROMLONLAT -122.4 37.8 BYRADIUS 5 km HGETALL restaurant:123
The GEO set is the spatial index. The Hash is the record. They are joined by the member name. This is the general pattern for any secondary index in Valkey: one structure holds the index (the ordering or location), a separate Hash holds the row, and the application fetches from both using the id as the join key.
The GEO set is a spatial index, not a record store. Every row lives in its own Hash, keyed by
the same name used as the GEO member. A search returns ids; a separate HGETALL per id fetches
the row. This two-step pattern is the standard secondary-index idiom in Valkey.
Real-time location tracking
geospatial.md.txt · Real-Time Location TrackingFor moving entities (drivers, delivery personnel), each GPS ping is a GEOADD. The command is
idempotent on the member name — calling it again moves the entity’s position without adding a
duplicate member. A companion Hash holds the availability state and timestamp:
# GPS ping updates the driver's position GEOADD drivers -122.4 37.8 "driver:456" # Availability and freshness in a companion Hash HSET driver:456:status last_update 1706648400 available 1 # Find nearby available drivers GEOSEARCH drivers FROMLONLAT -122.4 37.8 BYRADIUS 5 km COUNT 20
The application filters on availability and freshness after receiving the ids from GEOSEARCH:
fetch each driver:N:status Hash and discard stale or unavailable drivers. This is the same
separate-Hash pattern from the previous section — the GEO set holds the spatial index; the Hash holds
the operational state.
GEOADD is idempotent on the member name: a second call with new coordinates moves
the entity, not duplicates it. Each GPS ping is a single GEOADD; availability and freshness live
in a companion Hash.
Geofencing — application-layer enter / exit detection
geospatial.md.txt · GeofencingValkey does not provide built-in geofence events. Geofencing is an application-layer pattern:
- Store the geofence definition (centre coordinates and radius, or a bounding box).
- On each location update, run
GEOSEARCHto test whether the entity is inside the fence. - Compare the current membership result to the previous state.
- On a state change (inside → outside, or outside → inside), publish
an enter or exit event with
PUBLISH.
This is a poll-then-compare loop. The application owns the state machine; Valkey provides the spatial test
(GEOSEARCH) and the messaging bus (Pub/Sub). An entity’s membership in the result set of
a GEOSEARCH BYRADIUS is the fence test.
GEOSEARCH BYRADIUS as the fence test + PUBLISH on state change; the application
holds the previous state and detects the transition.
Geospatial is orthogonal to codemojex (a location-agnostic emoji-guessing game; players are not placed in space). The standalone example is the grounding — no codemojex surface applies here.
Geofencing on Valkey is a two-step application pattern: GEOSEARCH answers the
spatial membership question; the application detects enter/exit by comparing successive answers. The engine
provides no reactive trigger — the poll cadence determines the detection latency.
References
sources · relatedSources
- Valkey — GEOSEARCH —
BYRADIUS,BYBOX,FROMMEMBER,FROMLONLAT, and output options. - Valkey — GEOSEARCHSTORE — persisting results as a Sorted Set for downstream processing.
- Valkey — GEOADD — adding or updating member positions; idempotent on member name.
- Valkey — GEODIST — distance between two members in m / km / mi / ft.
Related in this course
- R7.06.3 · The geohash sorted setthe structure reveal: a GEO set IS a Sorted Set
- R7.05 · Vectors & similarity searchanother distance-based query structure
- R7.04 · Bitmapsthe modeling family: boolean flags in minimal memory