Node Redis Sorted Set Commands

08.31.2021

Intro

Sorted sets are a powerful data set used in redis. If you are familiar with binary search, you know the importance of having a presorted set to access items in log(n). This data type is often used in analytics and leaderboards. In this article, we will learn how to work with sorted sets in Redis and 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.

Sorted Set Data Type

We can create a Sorted Set and add a value to the set using the following. The example below is similar to creating a unique list so:

const movieRatings = [
  {
    key: "star-wars",
    score: 4,
  },
  {
    key: "marvel",
    score: 5,
  },
]

We can add items to a sorted set by using the zadd method. We pass in the name of the set, the score, then the key we want to add the score too.

// Sorted Set Add
await redis.zadd("movie-ratings", 4, "star-wars")
await redis.zadd("movie-ratings", 5, "marvel")

We can get the member of a sorted set using the zrange function. We pass the set name, the start index, then the end index.

// Sorted Set Range
const result = await redis.zrange("movie-ratings", 1, 3)
console.log(result) // [ 'marvel' ]

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() {
  // Sorted Set Add
  await redis.zadd("movie-ratings", 4, "star-wars")
  await redis.zadd("movie-ratings", 5, "marvel")

  // Sorted Set Range
  const result = await redis.zrange("movie-ratings", 1, 3)
  console.log(result)
}

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

Sorted Set Cardinality (Size)

If we want to get the size of our set, we can use zcard.

async function sortedSetSize() {
    // Sorted Set Count
    const result = await redis.zcard("movie-ratings")
    console.log(result) // 2
}

Sorted Set Count

We can count the number of items between a min and max value using the zcount method.

async function sortedSetCount() {
    // Sorted Set Count
    const result = await redis.zcount("movie-ratings", 4, 5)
    console.log(result) // 2

    const result2 = await redis.zcount("movie-ratings", 1, 3)
    console.log(result2) // 0
}

Sorted Set Range

Sorted set range will return a list of items within an index. We can also use 0, -1 to select all item in the set.

async function sortedSetRange() {
    // Sorted Set Range
    const result = await redis.zrange("movie-ratings", 1, 3)
    console.log(result) // [ 'marvel' ]

    const result2 = await redis.zrange("movie-ratings", 0, -1)
    console.log(result2) // [ 'star-wars', 'marvel' ]
}

Sorted Set Difference

To get the different or elements in one set and not another, we can use the zdiff function.

async function sortedSetDiff() {
    // Sorted Set Diff
    await redis.zadd("movie-ratings-user2", 3, "marvel")

    const numberOfSets = 2
    const result = await redis.zdiff(numberOfSets, "movie-ratings", "movie-ratings-user2")
    console.log(result) // [ 'star-wars' ]
}

Sorted Set Intersection

Similar to the above, we can use the zinter method to see the items shared amongst two sets.

async function sortedSetInter() {
    // Sorted Set Intersection
    await redis.zadd("movie-ratings-user2", 3, "marvel")

    const numberOfSets = 2
    const result = await redis.zinter(numberOfSets, "movie-ratings", "movie-ratings-user2")
    console.log(result) // [ 'marvel' ]
}

Sorted Set Increment By

If we want to increment a a score, we can use zincrby. Below we increment the rating of new-movie by 2.

async function sortedSetIncrementBy() {
    // Sorted Set Increment By
    await redis.zadd("movie-ratings", 4, "new-movie")
    await redis.zincrby("movie-ratings", 2, "new-movie")
}

Sorted Set Multiple Scores

If we have a list of keys, and we want to get their scores, we can use the zmscore.

async function sortedSetMultipleScore() {
    // Sorted Set Multiple Score
    const result = await redis.zmscore("movie-ratings", "star-wars", "marvel")
    console.log(result) // [ '4', '5' ]
}

Sorted Set Rank

To get the ranking of a specific item, think position on a leader board, we can use the zrank method.

async function sortedSetRank() {
    // Sorted Set Rank
    const result = await redis.zrank("movie-ratings", "star-wars")
    console.log(result) // 1

    const result2 = await redis.zrank("movie-ratings", "marvel")
    console.log(result2) // 2
}