class Redis::SortedSet

Class representing a sorted set.

Public Instance Methods

&(*sets)
Alias for: intersection
+(*sets)
Alias for: union
==(x) click to toggle source
# File lib/redis/sorted_set.rb, line 270
def ==(x)
  members == x
end
[](index, length=nil) click to toggle source

Same functionality as Ruby arrays. If a single number is given, return just the element at that index using Redis: ZRANGE. Otherwise, return a range of values using Redis: ZRANGE.

# File lib/redis/sorted_set.rb, line 39
def [](index, length=nil)
  if index.is_a? Range
    range(index.first, index.max)
  elsif length
    case length <=> 0
    when 1  then range(index, index + length - 1)
    when 0  then []
    when -1 then nil  # Ruby does this (a bit weird)
    end
  else
    result = score(index) || 0 # handles a nil score
  end
end
Also aliased as: slice
[]=(member, score) click to toggle source

How to add values using a sorted set. The key is the member, eg, “Peter”, and the value is the score, eg, 163. So:

num_posts['Peter'] = 163
# File lib/redis/sorted_set.rb, line 11
def []=(member, score)
  add(member, score)
end
add(member, score) click to toggle source

Add a member and its corresponding value to Redis. Note that the arguments to this are flipped; the member comes first rather than the score, since the member is the unique item (not the score).

# File lib/redis/sorted_set.rb, line 18
def add(member, score)
  allow_expiration do
    redis.zadd(key, score, marshal(member))
  end
end
add_all(values)
Alias for: merge
at(index) click to toggle source

Return the value at the given index. Can also use familiar list syntax. Redis: ZRANGE

# File lib/redis/sorted_set.rb, line 280
def at(index)
  range(index, index).first
end
count()
Alias for: length
decr(member, by=1)
Alias for: decrement
decrby(member, by=1)
Alias for: decrement
decrement(member, by=1) click to toggle source

Convenience to calling increment() with a negative number.

# File lib/redis/sorted_set.rb, line 184
def decrement(member, by=1)
  allow_expiration do
    zincrby(member, -by)
  end
end
Also aliased as: decr, decrby
delete(value) click to toggle source

Delete the value from the set. Redis: ZREM

# File lib/redis/sorted_set.rb, line 155
def delete(value)
  allow_expiration do
    redis.zrem(key, marshal(value))
  end
end
delete_if(&block) click to toggle source

Delete element if it matches block

# File lib/redis/sorted_set.rb, line 162
def delete_if(&block)
  raise ArgumentError, "Missing block to SortedSet#delete_if" unless block_given?
  res = false
  redis.zrange(key, 0, -1).each do |m|
    if block.call(unmarshal(m))
      res = redis.zrem(key, m)
    end
  end
  res
end
empty?() click to toggle source

Returns true if the set has no members. Redis: SCARD == 0

# File lib/redis/sorted_set.rb, line 266
def empty?
  length == 0
end
first() click to toggle source

Return the first element in the list. Redis: ZRANGE(0)

# File lib/redis/sorted_set.rb, line 285
def first
  at(0)
end
incr(member, by=1)
Alias for: increment
incrby(member, by=1)
Alias for: increment
increment(member, by=1) click to toggle source

Increment the rank of that member atomically and return the new value. This method is aliased as incr() for brevity. Redis: ZINCRBY

# File lib/redis/sorted_set.rb, line 175
def increment(member, by=1)
  allow_expiration do
    zincrby(member, by)
  end
end
Also aliased as: incr, incrby
inter(*sets)
Alias for: intersection
intersect(*sets)
Alias for: intersection
intersection(*sets) click to toggle source

Return the intersection with another set. Can pass it either another set object or set name. Also available as & which is a bit cleaner:

members_in_both = set1 & set2

If you want to specify multiple sets, you must use intersection:

members_in_all = set1.intersection(set2, set3, set4)
members_in_all = set1.inter(set2, set3, set4)  # alias

Redis: SINTER

# File lib/redis/sorted_set.rb, line 203
def intersection(*sets)
  result = nil
  temp_key = :"#{key}:intersection:#{Time.current.to_i + rand}"

  redis.multi do
    interstore(temp_key, *sets)
    redis.expire(temp_key, 1)

    result = redis.zrange(temp_key, 0, -1)
  end

  result.value
end
Also aliased as: intersect, inter, &
interstore(name, *sets) click to toggle source

Calculate the intersection and store it in Redis as name. Returns the number of elements in the stored intersection. Redis: SUNIONSTORE

# File lib/redis/sorted_set.rb, line 222
def interstore(name, *sets)
  allow_expiration do
    opts = sets.last.is_a?(Hash) ? sets.pop : {}
    redis.zinterstore(key_from_object(name), keys_from_objects([self] + sets), **opts)
  end
end
last() click to toggle source

Return the last element in the list. Redis: ZRANGE(-1)

# File lib/redis/sorted_set.rb, line 290
def last
  at(-1)
end
length() click to toggle source

The number of members in the set. Aliased as size or count. Redis: ZCARD

# File lib/redis/sorted_set.rb, line 295
def length
  redis.zcard(key)
end
Also aliased as: size, count
member?(value) click to toggle source

Return a boolean indicating whether value is a member.

# File lib/redis/sorted_set.rb, line 307
def member?(value)
  !redis.zscore(key, marshal(value)).nil?
end
members(options={}) click to toggle source

Return all members of the sorted set with their scores. Extremely CPU-intensive. Better to use a range instead.

# File lib/redis/sorted_set.rb, line 85
def members(options={})
  range(0, -1, options) || []
end
Also aliased as: value
merge(values) click to toggle source

Add a list of members and their corresponding value (or a hash mapping values to scores) to Redis. Note that the arguments to this are flipped; the member comes first rather than the score, since the member is the unique item (not the score).

# File lib/redis/sorted_set.rb, line 28
def merge(values)
  allow_expiration do
    vals = values.map{|v,s| [s, marshal(v)] }
    redis.zadd(key, vals)
  end
end
Also aliased as: add_all
range(start_index, end_index, options={}) click to toggle source

Return a range of values from start_index to end_index. Can also use the familiar list Ruby syntax. Redis: ZRANGE

# File lib/redis/sorted_set.rb, line 92
def range(start_index, end_index, options={})
  if options[:withscores] || options[:with_scores]
    redis.zrange(key, start_index, end_index, :with_scores => true).map{|v,s| [unmarshal(v), s] }
  else
    redis.zrange(key, start_index, end_index).map{|v| unmarshal(v) }
  end
end
range_size(min, max) click to toggle source

The number of members within a range of scores. Redis: ZCOUNT

# File lib/redis/sorted_set.rb, line 302
def range_size(min, max)
  redis.zcount(key, min, max)
end
rangebyscore(min, max, options={}) click to toggle source

Return the all the elements in the sorted set at key with a score between min and max (including elements with score equal to min or max). Options:

:count, :offset - passed to LIMIT
:withscores     - if true, scores are returned as well

Redis: ZRANGEBYSCORE

# File lib/redis/sorted_set.rb, line 114
def rangebyscore(min, max, options={})
  args = {}
  args[:limit] = [options[:offset] || 0, options[:limit] || options[:count]] if
            options[:offset] || options[:limit] || options[:count]
  args[:with_scores] = true if options[:withscores] || options[:with_scores]

  redis.zrangebyscore(key, min, max, **args).map{|v| unmarshal(v) }
end
rank(member) click to toggle source

Return the rank of the member in the sorted set, with scores ordered from low to high. revrank returns the rank with scores ordered from high to low. When the given member does not exist in the sorted set, nil is returned. The returned rank (or index) of the member is 0-based for both commands

# File lib/redis/sorted_set.rb, line 67
def rank(member)
  if n = redis.zrank(key, marshal(member))
    n.to_i
  else
    nil
  end
end
remrangebyrank(min, max) click to toggle source

Remove all elements in the sorted set at key with rank between start and end. Start and end are 0-based with rank 0 being the element with the lowest score. Both start and end can be negative numbers, where they indicate offsets starting at the element with the highest rank. For example: -1 is the element with the highest score, -2 the element with the second highest score and so forth. Redis: ZREMRANGEBYRANK

# File lib/redis/sorted_set.rb, line 144
def remrangebyrank(min, max)
  redis.zremrangebyrank(key, min, max)
end
remrangebyscore(min, max) click to toggle source

Remove all the elements in the sorted set at key with a score between min and max (including elements with score equal to min or max). Redis: ZREMRANGEBYSCORE

# File lib/redis/sorted_set.rb, line 150
def remrangebyscore(min, max)
  redis.zremrangebyscore(key, min, max)
end
revrange(start_index, end_index, options={}) click to toggle source

Return a range of values from start_index to end_index in reverse order. Redis: ZREVRANGE

# File lib/redis/sorted_set.rb, line 101
def revrange(start_index, end_index, options={})
  if options[:withscores] || options[:with_scores]
    redis.zrevrange(key, start_index, end_index, :with_scores => true).map{|v,s| [unmarshal(v), s] }
  else
    redis.zrevrange(key, start_index, end_index).map{|v| unmarshal(v) }
  end
end
revrangebyscore(max, min, options={}) click to toggle source

Returns all the elements in the sorted set at key with a score between max and min (including elements with score equal to max or min). In contrary to the default ordering of sorted sets, for this command the elements are considered to be ordered from high to low scores. Options:

:count, :offset - passed to LIMIT
:withscores     - if true, scores are returned as well

Redis: ZREVRANGEBYSCORE

# File lib/redis/sorted_set.rb, line 130
def revrangebyscore(max, min, options={})
  args = {}
  args[:limit] = [options[:offset] || 0, options[:limit] || options[:count]] if
            options[:offset] || options[:limit] || options[:count]
  args[:with_scores] = true if options[:withscores] || options[:with_scores]

  redis.zrevrangebyscore(key, max, min, **args).map{|v| unmarshal(v) }
end
revrank(member) click to toggle source
# File lib/redis/sorted_set.rb, line 75
def revrank(member)
  if n = redis.zrevrank(key, marshal(member))
    n.to_i
  else
    nil
  end
end
score(member) click to toggle source

Return the score of the specified element of the sorted set at key. If the specified element does not exist in the sorted set, or the key does not exist at all, nil is returned. Redis: ZSCORE.

# File lib/redis/sorted_set.rb, line 57
def score(member)
  result = redis.zscore(key, marshal(member))

  result.to_f unless result.nil?
end
size()
Alias for: length
slice(index, length=nil)
Alias for: []
to_s() click to toggle source
# File lib/redis/sorted_set.rb, line 274
def to_s
  members.join(', ')
end
union(*sets) click to toggle source

Return the union with another set. Can pass it either another set object or set name. Also available as | and + which are a bit cleaner:

members_in_either = set1 | set2
members_in_either = set1 + set2

If you want to specify multiple sets, you must use union:

members_in_all = set1.union(set2, set3, set4)

Redis: SUNION

# File lib/redis/sorted_set.rb, line 240
def union(*sets)
  result = nil
  temp_key = :"#{key}:union:#{Time.current.to_i + rand}"

  redis.multi do
    unionstore(temp_key, *sets)
    redis.expire(temp_key, 1)

    result = redis.zrange(temp_key, 0, -1)
  end

  result.value
end
Also aliased as: |, +
unionstore(name, *sets) click to toggle source

Calculate the union and store it in Redis as name. Returns the number of elements in the stored union. Redis: SUNIONSTORE

# File lib/redis/sorted_set.rb, line 258
def unionstore(name, *sets)
  allow_expiration do
    opts = sets.last.is_a?(Hash) ? sets.pop : {}
    redis.zunionstore(key_from_object(name), keys_from_objects([self] + sets), **opts)
  end
end
value(options={})
Alias for: members
|(*sets)
Alias for: union

Private Instance Methods

key_from_object(set) click to toggle source
# File lib/redis/sorted_set.rb, line 312
def key_from_object(set)
  set.is_a?(Redis::SortedSet) ? set.key : set
end
keys_from_objects(sets) click to toggle source
# File lib/redis/sorted_set.rb, line 316
def keys_from_objects(sets)
  raise ArgumentError, "Must pass in one or more set names" if sets.empty?
  sets.collect{|set| set.is_a?(Redis::SortedSet) || set.is_a?(Redis::Set) ? set.key : set}
end
zincrby(member, by) click to toggle source
# File lib/redis/sorted_set.rb, line 321
def zincrby(member, by)
  redis.zincrby(key, by, marshal(member)).to_i
end