Node Redis Geo Commands

09.02.2021

Intro

Geocoding and coordinates are a common use case in modern applications. These computations can be very heavy in terms of lookups so it is often desired to cache. Thus, Redis provides us with the geo data type to make using coordinates easy. In this article, we will learn how to use the Geo Data Type in Redis with Nodejs.

Setting up Redis

For setting up Redis, I would recommend using a service for you in prod. Azure for example, has a great redis service that scales easily. However, you will want to learn redis and eventually how to scale it yourself. This will help with debugging cloud services or eventually, saving money and not using them.

We will start our intro to redis via using docker compose. Create a docker-compose.yml file and add the following.

version: "3.2"
services:
  redis:
    image: "redis:alpine"
    command: redis-server
    ports:
      - "6379:6379"
    volumes:
      - $PWD/redis-data:/var/lib/redis
      - $PWD/redis.conf:/usr/local/etc/redis/redis.conf
    environment:
      - REDIS_REPLICATION_MODE=master

Ensure you have docker installed and run

docker-compose up

Installing Redis Modules

There are two modules I see often used in nodejs. I will tend towards ioredis as it has built in support for promises and many other features in redis.

npm install ioredis

Writing the Code

Let's open up a new file, index.js and go through many of the common commands you will used with lists in redis.

Geo Add with the Geo Data Type

We can add items to a geo set using the following. The example below will create a Geo Set called Sicilty that is a sorted set. We will then add Palermo then add Catania with their respective longitude and latitude.

// Geo  Add
await redis.geoadd("Sicily", 13.361389, 38.115556, "Palermo")
await redis.geoadd("Sicily", 15.087269, 37.502669, "Catania")

For each of the examples below, I will use the following template to run all the commands. Here is my full index file. We will just replace the commands each time.

const Redis = require("ioredis")

const redis = new Redis({})

async function main() {
  // Geo  Add
  await redis.geoadd("Sicily", 13.361389, 38.115556, "Palermo")
  await redis.geoadd("Sicily", 15.087269, 37.502669, "Catania")
}

(async () => {
    await main()
})()

Geo Distance

Once we have a geo set, we can start to do calulcations on it. For example, we can get the distance between two members using the following.

// Geo Dist
const result = await redis.geodist("Sicily", "Palermo", "Catania")
console.log(result) // 166274.1516

Geo Radius (Search)

We can also get all items within a radius using the georadius command.

// Geo Radius - key for geo hash, long, latitude, radius, unit
const result = await redis.georadius("Sicily", 15, 27, 200, "km")
console.log(result) // 2

Geo Hash

If we would like to get the specific hash for our geo sets, we can use geohash

// Geo Hash
const result = await redis.geohash("Sicily", "Palermo", "Catania")
console.log(result) // [ 'sqc8b49rny0', 'sqdtr74hyu0' ]

Geo Positin

The geopos class will return the position of members in our geo hash.

// Geo Position
const result = await redis.geopos("Sicily", "Palermo", "Catania", "Random")
console.log(result) 
// [
//     [ '13.36138933897018433', '38.11555639549629859' ],
//     [ '15.08726745843887329', '37.50266842333162032' ],
//     null
//  ]

Geo Distance

To get the distance between two members, we can use the geodist command. We have the option to specificy the units.

 // Geo Distance
const result = await redis.geodist("Sicily", "Palermo", "Catania")
console.log(result) // 166274.1516

const result2 = await redis.geodist("Sicily", "Palermo", "Catania", "km")
console.log(result2) // 166.2742

Geo Search

The geosearch command provides an api to allow us to search the geo members of our set.

// Geo Search
const result = await redis.geosearch("Sicily", "FROMLONLAT", 15, 37, "BYRADIUS", 200, "km", "ASC")
console.log(result) // [ 'Catania', 'Palermo' ]