如何在Redis中将有序集合与哈希表联接?

3
在Redis中,假设我有一个按时间戳评分的ID有序集合:
(name of ordered set) someobject:media

Member | Score
1        1442784376400
2        1442784376420
3        1442784376450

每个成员都是哈希的ID(像这样):

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

是否有一种原子操作可以让我获取someobject:media成员的所有哈希值?

我正在使用Node Redis,理论上它提供了redis-cli提供的所有操作(正如人们所期望的那样)。

到目前为止,我唯一的想法是像这样循环遍历每一个元素:

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
  });
});

我的直觉告诉我Redis提供了某种原子"join"类型操作,但也许我是错的。上述方法看起来完全低效。
换句话说,我想要加入所有someobject:media有序集合中的media:<id>。这可行吗?
3个回答

4

我认为 sort 无法与哈希一起使用。你可以使用multi模式,它仍然是高效的。在Redis中,多元是比类似于连接更典型的方法。可以尝试这样做:

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

     });
});

谢谢,这看起来更接近了。不知道能不能在这种操作中使用 SCAN 呢?比如我想获取所有 media:* 的哈希值。 - Josh Beam
我认为如果你想以迭代的基于游标的方式处理大量成员,每次获取少量数据而不是在每次调用中检索大量数据,那么你可以使用zscan。 - Jason Livesay
实际上,在这里你需要的不是MULTI,而是流水线处理,但我相信在这种情况下最终结果应该是一样的。 - Itamar Haber
这个解决方案完美地解决了问题。SORT 解决方案几乎可以,但我无法找到一种方法来获取它返回的排序集合中项目的实际 score,只能得到成员键。使用这个解决方案,我们可以从 zrange 调用中获取分数,并手动将其解析为哈希项。 - Brandon

1

我的Redis已经非常生疏了,但我认为你想使用(名字令人困惑的)SORT命令来实现这个目的。类似这样:

SORT someobject:media BY nosort GET media:*

我没有使用过node_redis,但我认为这大致相当于:

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

非常感谢。这对于列表看起来很棒。你知道是否可以用于排序集合吗?我没有看到排序集合命令 SORT - Josh Beam
文档中说:“返回或存储在key中包含的列表、集合或排序集合中的元素。”据我所知,您无需特别操作即可将其与排序集合一起使用。 - Jordan Running
我认为你不能使用那个来检索哈希。请看我的回答。 - Jason Livesay
@Jason,你说得对。我正在查看文档,你确实无法获取完整的哈希值(但是,有时可以从哈希中获取一个字段,这可能很有用)。例如,您可以通过执行sort someobject:media by nosort get media:*->some_field来排序someobject:media并获取some_field字段。 - Josh Beam

0
你可以使用一个排序命令,但是你必须明确指定所有哈希字段的名称。对于你的例子,应该是这样的:
sort someobject:media get media:*->name get media:*->time
1) "something"
2) "1442784376400"
3) "somethingelse"
4) "1442784376420"
5) (nil)
6) (nil)

为了更方便地阅读答案,您可以添加get #以获取索引:
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)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接