Node.js & redis / zadd objects to a set

12,053

Solution 1

Issue 1 -- sorted set keys

Try stringifying the JSON you are using as the keys of your sorted set. For example,

dbclient1.zadd("myprivateset", 3, {"guid":"abab-baba", "data-persistent":"xxxx", "size":"20"}) 

needs to be:

dbclient1.zadd("myprivateset", 3, JSON.stringify({"guid":"abab-baba", "data-persistent":"xxxx", "size":"20"})) 

Without stringifying the keys, every zadd will use the key [object Object] overwriting each time. That is, you'll only ever have one item in your sorted set that is unidentifiable (other than by [object Object]).

Issue 2 -- fetching data

Also, hgetall is not the redis command to use for retrieving data in a redis sorted set. You'll want to focus on sorted set specific commands. A list of redis commands are listed here: http://redis.io/commands

Solution 2

My two cents, building on comments by @leonid-beschastny and @cpentra1. I recommend using redis.multi(). It allows for several calls in a batch, and as you can see in the example, as soon as the three elements are added to the ordered set, we can perform a zrangebyscore in the same multi batch and get the expected results. Instructions can be created dynamically. The replies array when multi.exec() is invoked returns the results for each of the multi operations, in order.

var db = require("redis");
var dbclient1 = db.createClient();
var multi = dbclient1.multi();

// We use JSON.stringify() as suggested by @cpentra1 
multi.zadd("myprivateset", 3, JSON.stringify({"guid":"abab-baba", "data-persistent":"xxxx", "size":"20"}));
multi.zadd("myprivateset", 2, JSON.stringify({"guid":"abab-baba3", "data-persistent":"xxxx", "size":"20"}));
multi.zadd("myprivateset", 2, JSON.stringify({"guid":"abab-dafa3", "data-persistent":"yyyy", "size":"21"}));
multi.zrangebyscore("myprivateset", 1, 4);
multi.zcard("myprivateset"); // The total number of elements in the set
multi.exec(function(err, replies) {
    console.log(replies)
    // Will output something like:
    // [ 1,
    //   1,
    //   1,
    //   [ '{"guid":"abab-baba3","data-persistent":"xxxx","size":"20"}',
    //     '{"guid":"abab-dafa3","data-persistent":"yyyy","size":"21"}',
    //     '{"guid":"abab-baba","data-persistent":"xxxx","size":"20"}' ],
    //   3 ]
});

Note: if you run the same example twice, instead of 1s in the first three elements of the replies array, you'll get 0s as the same member with the same score cannot be added twice.

Solution 3

Seems like with Redis 6.2 the format has changed to and object with score and value attributes or an array of those, like this:

async function sortedSet() {
  let client;
  try {
    client = createClient();

    client.on("error", (err) => console.log("Redis Client Error", err));

    await client.connect();
    console.log("connected");

    await client.zAdd("user:0:followers", [{score: "1", value: "John"}, {score: "2", value: "Other John"}]);
    console.log("sorted set added");

  } finally {
    await client.quit();
  }
}

sortedSet("duto_guerra", "with hashes");

In case you are wondering, I figured this out by reading the source code for node-redis ZADD

Share:
12,053

Related videos on Youtube

MIDE11
Author by

MIDE11

Updated on September 16, 2022

Comments

  • MIDE11
    MIDE11 over 1 year

    I have the following code:

    var db = require("redis");
    var dbclient1 = db.createClient();
    
    dbclient1.zadd("myprivateset", 3, {"guid":"abab-baba", "data-persistent":"xxxx", "size":"20"})
    dbclient1.zadd("myprivateset", 2, {"guid":"abab-baba3", "data-persistent":"xxxx", "size":"20"})
    dbclient1.zrangebyscore("myprivateset", 1, 4)
    dbclient1.hgetall("myprivateset", function(err, rep){
     console.log(rep);
    });
    

    I wish to store my objects (in JSON format) in a sorted set, which determine by the score (3 & 2 in our case).

    For some reason, when I print this table (rep), I get undefined.

    What I do wrong?

  • MIDE11
    MIDE11 almost 9 years
    It still prints undefined
  • cpentra1
    cpentra1 almost 9 years
    I don't think hgetall is what you want.
  • cpentra1
    cpentra1 almost 9 years
    // returns all in score range from 1-4 dbclient1.zrangebyscore("myprivateset", 1, 4, function(err, rep) { console.log(rep); }); // returns paginated from 0 to 5 dbclient1.zrevrange("myprivateset", 0, 5, function(err, rep) { console.log(rep); });
  • cpentra1
    cpentra1 almost 9 years
    HGETALL is for hashes, and you're using a sorted set so you'll want to use sorted set retrieval methods instead of hash ones to access the data. (redis.io/commands)
  • kdragger
    kdragger over 2 years
    thanks. i was getting super frustrated and the docs don't mention sorted sets specifically, that it is zAdd (not zadd), or this new format.
  • Nandeep Mali
    Nandeep Mali about 2 years
    Thank you for this. Had no idea that we had to use a list of score and value pairs. Really got me frustrated.