Redis GEO commands store longitude/latitude points and answer "what's near here?" in milliseconds, which covers store locators, nearby drivers and couriers, "people near you" and geofencing without a spatial database. A GEO set is a Sorted Set whose scores are geohashes, so each member is a unique location ID.
Add locations​
AddGeoMember adds or moves one member, and AddGeoMembers adds several in one command. Arguments are
longitude first, then latitude:
using var redis = redisManager.GetClient();
redis.AddGeoMembers("stores",
new RedisGeo(-122.4194, 37.7749, "store:sf-downtown"),
new RedisGeo(-122.2711, 37.8044, "store:oakland"),
new RedisGeo(-122.0322, 37.3230, "store:cupertino"),
new RedisGeo(-118.2437, 34.0522, "store:los-angeles"));
Store only the ID in the GEO set and keep each location's details, like name, address and opening hours, in its own key. Valid longitudes are -180 to 180, and latitudes -85.05 to 85.05.
Find what's nearby​
FindGeoResultsInRadius returns members within a radius of a point, with their distance and coordinates.
Limit the count and sort by distance to get the nearest results:
List<RedisGeoResult> nearby = redis.FindGeoResultsInRadius("stores",
longitude: -122.4089, latitude: 37.7837,
radius: 25, unit: RedisGeoUnit.Kilometers,
count: 5, sortByNearest: true);
foreach (var store in nearby)
Console.WriteLine($"{store.Member}: {store.Distance:N1} km");
// store:sf-downtown: 1.3 km
// store:oakland: 12.3 km
RedisGeoUnit provides Meters, Kilometers, Miles and Feet. Use FindGeoMembersInRadius when you only need
the member IDs:
string[] ids = redis.FindGeoMembersInRadius("stores", -122.4089, 37.7837, 25, RedisGeoUnit.Kilometers);
Both also accept an existing member as the center, e.g. stores within 15 km of another store:
string[] closeBy = redis.FindGeoMembersInRadius("stores", "store:sf-downtown", 15, RedisGeoUnit.Kilometers);
// store:sf-downtown, store:oakland
Distances and coordinates​
double km = redis.CalculateDistanceBetweenGeoMembers("stores",
"store:sf-downtown", "store:los-angeles", RedisGeoUnit.Kilometers); // ~559
List<RedisGeo> coords = redis.GetGeoCoordinates("stores", "store:oakland");
string[] hashes = redis.GetGeohashes("stores", "store:oakland"); // e.g. for map tiles
Distances are calculated on a sphere, accurate to within 0.5%, which is ample for "nearest store" and "distance to driver" but not for surveying.
Track moving objects​
Updating a member's position is the same AddGeoMember call: a member is never duplicated, it moves. That
makes tracking live positions, such as delivery drivers, a single command per location update:
// Each driver's app reports its position every few seconds
redis.AddGeoMember("drivers:available", lng, lat, $"driver:{driverId}");
// Find the 3 closest available drivers to a pickup
var closest = redis.FindGeoResultsInRadius("drivers:available", pickupLng, pickupLat,
5, RedisGeoUnit.Kilometers, count: 3, sortByNearest: true);
// Remove a driver when they accept a job or go offline
redis.RemoveItemFromSortedSet("drivers:available", $"driver:{driverId}");
GEO members don't expire individually. To drop drivers whose app stopped reporting, keep their last-seen time in a second Sorted Set and periodically remove stale members from both:
var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
redis.AddItemToSortedSet("drivers:last-seen", $"driver:{driverId}", now); // on every update
// Periodically: remove drivers not seen in the last 2 minutes
var stale = redis.GetRangeFromSortedSetByLowestScore("drivers:last-seen", 0, now - 120);
if (stale.Count > 0)
{
redis.RemoveItemsFromSortedSet("drivers:available", stale);
redis.RemoveItemsFromSortedSet("drivers:last-seen", stale);
}
Geofencing​
To check whether a point is within range of a location, query a small radius around the point and look for the location's ID, or compare the distance directly:
redis.AddGeoMember("geofence:warehouses", -122.39, 37.77, "warehouse:sf");
redis.AddGeoMember("geofence:warehouses", deliveryLng, deliveryLat, "delivery:42");
var meters = redis.CalculateDistanceBetweenGeoMembers("geofence:warehouses",
"warehouse:sf", "delivery:42", RedisGeoUnit.Meters);
bool arrived = meters < 200;
Async​
await using var redis = await redisManager.GetClientAsync(token);
await redis.AddGeoMemberAsync("stores", -122.4194, 37.7749, "store:sf-downtown", token);
var nearby = await redis.FindGeoResultsInRadiusAsync("stores", -122.4089, 37.7837,
25, RedisGeoUnit.Kilometers, count: 5, sortByNearest: true, token: token);
For a complete example app, see Redis GEO, which finds US cities near any point on an interactive map.