Josh Beam
Josh Beam

Reputation: 19772

How do you join an ordered set with hashes in Redis?

In Redis, say I have an ordered set of IDs (which are scored by a timestamp):

(name of ordered set) someobject:media

Member | Score
1        1442784376400
2        1442784376420
3        1442784376450

Each member is an ID of a hash (like this):

media:1      { 'name': 'something', 'timestamp': '1442784376400 }
media:2      { 'name': 'somethingelse', 'timestamp': '1442784376420' }
// and so forth

Is there an atomic operation that would allow me to get all the hashes for the members of someobject:media?

I'm using Node Redis, which in theory provides all the operations that redis-cli provides (as one would expect).

So far, my only thought is to loop through everything, like this:

client.zrevrange(['someobject:media', 0, -1], (err, res) => {
  let promises = res.map(mediaId => {
    return new Promise((resolve, reject) => {
      client.hgetall('media:' + mediaId, (err, res) => {
        resolve(res);
      });
    });
  });

  Promise.all(promises).then(result => {
    // do something with the "media" hashes
  });
});

My gut tells me there is some sort of atomic "join" type operation that Redis provides, but maybe I'm wrong. The above method looks entirely inefficient.

In other words, I want to join on all media:<id> from the ordered set of someobject:media. Is this possible?

Upvotes: 3

Views: 1050

Answers (3)

Ofir Luzon
Ofir Luzon

Reputation: 10907

You can use one sort command, but you must explicitly specify all hash fields names. For your example, it would be:

sort someobject:media get media:*->name get media:*->time
1) "something"
2) "1442784376400"
3) "somethingelse"
4) "1442784376420"
5) (nil)
6) (nil)

For easier reading of the answer, you can add get # to get the index as well:

sort someobject:media get # get media:*->name get media:*->time
1) "1"
2) "something"
3) "1442784376400"
4) "2"
5) "somethingelse"
6) "1442784376420"
7) "3"
8) (nil)
9) (nil)

Upvotes: 0

Jason Livesay
Jason Livesay

Reputation: 6377

I don't think sort works with hashes. You can use multi mode and it will still be efficient. Multi is more typical in redis than something like a join. Something like this:

client.zrange("members", 0, 100, function (err, replies) {
     var m = client.multi()
     replies.forEach(function(item) {
         m.hgetall(item);
     });
     m.exec(function(err, hashes) {

     });
});

Upvotes: 4

Jordan Running
Jordan Running

Reputation: 106037

My Redis is suuuuper rusty, but I think you want to use the (confusingly-named) SORT command for this. Something like:

SORT someobject:media BY nosort GET media:*

I've not used node_redis but I think this translates to something like this:

client.sort([ "someobject:media", "by", "nosort", "get", "media:*" ], (err, res) =>
  // ...
});

Upvotes: 1

Related Questions