Node.js & redis / zadd objects to a set
Asked Answered
F

3

7

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?

Florie answered 9/6, 2015 at 7:18 Comment(1)
Node.js is async. You can't write something to DB and then immediately read it.Jenson
A
6

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

Augustusaugy answered 9/6, 2015 at 7:26 Comment(4)
It still prints undefinedFlorie
I don't think hgetall is what you want.Augustusaugy
// 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); });Augustusaugy
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)Augustusaugy
I
4

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

Incunabula answered 2/12, 2021 at 3:5 Comment(2)
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.Elissa
Thank you for this. Had no idea that we had to use a list of score and value pairs. Really got me frustrated.Lavena
D
3

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.

Dysthymia answered 18/8, 2015 at 5:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.