人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

Ruby on Rails のモデルのDBリクエストに悩んでいます。
User, Itemモデルと、両者をつなぐ Bookmark (user, item) 、Follow(user, user)の4モデルがあるのですが、
「過去X時間で最もブックマークされたItem X件」とか、「最近友達がブックマークしたItem X件」といった、ちょっと複雑なリクエストの仕方がイマイチよくわかりません。

こういう風にやれば取得できる!!という定番はあるのでしょうか?

●質問者: fladdict
●カテゴリ:コンピュータ ウェブ制作
○ 状態 :終了
└ 回答数 : 3/3件

▽最新の回答へ

1 ● masuidrive

「過去X時間で最もブックマークされたItem X件」は、

bookmarks = Bookmark.group("item_id").select("*, count('item_id') AS cnt").order("cnt DESC")

これで、cntで取り出せます。

ex) p bookmakrs.map(&:cnt)


実は、MySQL/SQLiteなどのSQL DBではタイムライン処理のようなモノが難しいです。

http://labs.cybozu.co.jp/blog/kazuho/archives/2008/06/friends_timeline.php


fladdictさんのコメント
うわー、ぱっとやり方が見つからないと思ったら、やっぱりゴニャゴニャと色々やらなきゃならないんですね。 初期のTwitterのfollow上限が1000だったりしたのは、この辺が原因なのかしらですね。

2 ● highhill

サーバーはmySQLですかね?そうだったら、mySQL側で、SQLでガリガリ組んで、viewを作ったらどうでしょうかね?
MySQL :: MySQL 5.1 リファレンスマニュアル :: 20.2 CREATE VIEW 構文
Ruby on Railsは知らないんですが、viewだったら、テーブルとして定義されるので、普通にマッピング出来るはず。

それで、肝心のSQLですが、サブクエリで、fromの中にいろいろごにょごにょ入れられるので、それでやってみる事が出来ると思いますよ。

Rubyでも、直接SQLの発行が出来ると思うので、
Ruby on Rails - Rails で、SQL分を直接実行する場合 - gendosuの企画開発室

サブクエリを使ってごにょごにょSQLを組み立てるのもいいかも。
これは僕がcakePHPで作ったサンプルのスクリーンショット。
no title

ORMで複雑なクエリをいろいろすると凄く遅いので、SQLで解決するのが一番パフォーマンスいいと思います。


3 ● labocho
class User < ActiveRecord::Base
 has_many :follows, foreign_key: :follower_id
end

class Item < ActiveRecord::Base
 has_many :bookmarks
 
 scope :bookmarked,
 select("items.*, COUNT(bookmarks.id) AS bookmark_count").
 joins(:bookmarks).
 group("bookmarks.item_id")

 scope :recently_bookmarked, proc {|n|
 t = n.hours.ago
 bookmarked.
 where("bookmarks.created_at > ?", t).
 order("bookmark_count DESC")
 }
 
 scope :recently_bookmarked_by_followee, proc{|n, follower|
 followee_ids = follower.follows.map{|f| f.followee_id }
 recently_bookmarked(n).
 where("bookmarks.user_id IN (?)", followee_ids)
 }
end

# 過去 x 時間以内に最もブックマークされた Item を n 件
Item.recently_bookmarked(x).limit(n)

# user がフォローしてるユーザに、過去 x 時間以内に最もブックマークされた Item を n 件
Item.recently_bookmarked_by_followee(x, user).limit(n)

定番かどうかわかりませんが、こんな感じでしょうか。ほとんど SQL ですが、scope で抽象化すると使いやすいです。

後者は JOIN のみでも可能ですが、これくらいが複雑になりすぎず好みです。実際には follower.followee_ids みたいなメソッドを作ってキャッシュするなどしてます。

データベースの VIEW を作るのも良いですが、Rails だとテーブルと対応したモデルと別のクラスになってしまうのが悩みどころですね。

関連質問

●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ