Hashes

Our ultimate objective in this section is to programmatically store JavaScript objects in Redis, and we'll learn about manipulating Redis hashes using Node.js in the process. Shamu is back to provide us with a real (Sea) world context.

const shamu = {
    type: 'killer whale',
    age: 5,
    lastFeedDate: 'Jan 06 2018',
}

Shamu

Set Field Values in a Redis Hash One by One

As a first approach, we'll marshal the shamu object into a Redis hash one field at a time:

const Redis = require('ioredis');

const redis = new Redis();

async function main() {
    const shamu = {
        type: 'killer whale',
        age: 5,
        lastFeedDate: 'Jan 06 2018',
    };

    try {
        const key = 'shamu';

        for (const prop in shamu) {
            console.log(prop, shamu[prop]);
            const result = await redis.hset(key, prop, shamu[prop]);
            console.log(result);
        }
    }
    catch (error) {
        console.error(error);
    }
    redis.disconnect();
}

main();

Beginning in line 15, we iterate over the properties of the shamu object and use the hset function to update each individual field of our Redis hash. This approach works; nonetheless, there is clearly a lot of impedance mismatch between the JavaScript object and the Redis hash. Is there a better way? I'm glad you asked. :wink:

Store JavaScript Objects in Redis using HMSET

The HMSET command handles our dilemma and enables us to set a Redis hash directly from a JavaScript object:

const Redis = require('ioredis');

const redis = new Redis();

async function main() {
    const shamu = {
        type: 'killer whale',
        age: 5,
        lastFeedDate: 'Jan 06 2018',
    };

    try {
        const key = 'shamu';
        const result = await redis.hmset(key, shamu);
        console.log(result);
    }
    catch (error) {
        console.error(error);
    }
    redis.disconnect();
}

main();

On line 14, we simply supply the shamu JavaScript object as the second parameter of the hmset function. This is way more elegant. Take a minute to soak this in: Redis can directly store JavaScript objects.

:warning: Warning :warning:

There are, however, some limitations to this approach as it does not work with nested JavaScript objects. Let's consider the following revised Shamu object:

const shamu = {
    type: 'killer whale',
    age: 5,
    lastFeedDate: 'Jan 06 2018',
    size: { length: 30, weight: 8 },
};

The hmset function will faithfully execute without error, but the fields of the nested size object will be unreadable. This can be verified without code by invoking the hgetall command from the redis-cli:

$ redis-cli hgetall shamu
1) "type"
2) "killer whale"
3) "age"
4) "5"
5) "lastFeedDate"
6) "Jan 06 2018"
7) "size"
8) "[object Object]"

While all the other Shamu properties are accessible, the size object is not.

Is there an even better way to store JavaScript objects in Redis? Absolutely, and I'll show you that next.

Store JavaScript Objects in Redis (The Best Way)

Since strings are the primary lingua franca in the Redis world, we can stringify our shamu JavaScript object to successfully store it in Redis:

const Redis = require('ioredis');

const redis = new Redis();

async function main() {
    const shamu = {
        type: 'killer whale',
        age: 5,
        lastFeedDate: 'Jan 06 2018',
        size: { length: 30, weight: 8 },
    };

    try {
        const key = 'shamu';
        const result = await redis.set(key, JSON.stringify(shamu));

        // Turn around and bring back Shamu immediately to prove it works.
        const shamuReturns = JSON.parse(await redis.get(key));
        console.log(shamuReturns);
    } catch (error) {
        console.error(error);
    }
    redis.disconnect();
}

main();

In line 15, we use the good old-fashioned set command to store our stringified shamu JavaScript object.

In line 18, we employ JSON.parse to rehydrate the shamu object returned from Redis.

The program returns the following console output, proving that our storage and retrieval of the JavaScript object was successful:

{ type: 'killer whale',
  age: 5,
  lastFeedDate: 'Jan 06 2018',
  size: { length: 30, weight: 8 } }

This approach provides an excellent general-purpose solution for storing both simple and more complex JavaScript objects with nested values within Redis.

Get Field Values from a Redis Hash

Back to our regularly scheduled program :tv: regarding Redis hashes, we can use the hgetall function to retrieve all field values from the shamu hash:

const Redis = require('ioredis');

const redis = new Redis();

function printObjectDetails(key, obj) {
    console.log(`${key} object`)
    console.log('-'.repeat(26));
    for (const prop in obj) {
        console.log(`${prop} = ${obj[prop]}`);
    }
}

async function main() {
    try {
        const key = 'shamu';
        const shamuObject = await redis.hgetall(key);
        printObjectDetails(key, shamuObject);
    } catch (error) {
        console.error(error);
    }
    redis.disconnect();
}

main();

The printObjectDetails function provides a convenient way to print the contents of the retrieved shamu hash to the console.

results matching ""

    No results matching ""