概要
Redis等のKVSでランキングロジックを持っていて、
その詳細データはMySQL等のRDSで持つことが少なからずあると思う。
kvsで取得した複数のidをactive_recordで指定した順序通りに取得したい。
ただしそのままにやると…
pry(main)> array = [1, 6, 3, 10, 7]
=> [1, 6, 3, 10, 7]
pry(main)> User.find(array).collect(&:id)
=> [1, 3, 6, 7, 10]
順序が変わって出力されてしまう。
それを解決する方法をまとめてみた。
内容
結論は
Something.find(array_of_ids).index_by(&:id).slice(*array_of_ids).values
例はこんな感じ
pry(main)> array = [1, 6, 3, 10, 7]
=> [1, 6, 3, 10, 7]
pry(main)> User.find(array).index_by(&:id).slice(*array).values.collect(&:id)
=> [1, 6, 3, 10, 7]
簡単に解説していく
index_by(&:id)
# index_byを使うことでこの形式ではなく
[
#<data1>,
#<data2>,
#<data3>, ...
]
# この形式になる
{
:id => #<data1>,
:id => #<data2>,
:id => #<data3>, ...
}
# 上記の例だと下記のようになる
{
1 => #<user1>,
3 => #<user3>,
6 => #<user6>, ...
}
slice(*array)
# sliceを使うと指定したkeyのhashを返す。
# 配列をそのまま渡してももちろんダメ
hash = {1 => "1", 2 => "2", 4 => "4"}.slice([4,1])
=> {}
# 下記の用に引数展開で渡してあげる
hash = {1 => "1", 2 => "2", 4 => "4"}.slice(*[4,1])
=> {4=>"4", 1=>"1"}
# なので、これでも意味は同じ
hash = {1 => "1", 2 => "2", 4 => "4"}.slice(4,1)
=> {4=>"4", 1=>"1"}
values
# そしてそのhashの値だけをとってくる。
pry(main)> hash = {1 => "1", 2 => "2", 4 => "4"}.slice(4,1)
=> {4=>"4", 1=>"1"}
pry(main)> hash.values
=> ["4", "1"]
こんな感じでやれば指定した順序どおりに取得することが出来る。
参考