【问题标题】:Ruby on Rails optimal search with array of filter values?Ruby on Rails 使用过滤器值数组进行最佳搜索?
【发布时间】:2016-07-20 13:43:04
【问题描述】:

我有一个具体的例子,但一般的问题是:当您有一组过滤器值要匹配时,检索记录的最佳方法是什么?

假设我有UserPost 记录其中用户has_many :posts

我有一个Relationship 模型,看起来像这样:

class Relationship < ActiveRecord::Base
  belongs_to :follower, class_name: "User"
  belongs_to :followed, class_name: "User"
  validates :follower_id, presence: true
  validates :followed_id, presence: true
end

我想编写一个函数,从您的关注者的关注中返回按时间顺序排列的帖子 - 即您关注的用户正在关注的用户的所有帖子,不包括重复和您关注的任何人的帖子。

我的解决方案是首先编译一个包含所有感兴趣用户的数组:

users = []
@user.following.each do |f|
  f.following.each do |ff|
    users << ff
  end
end

# dedupe
users = users.uniq

#remove self and following
users.delete(@user)
@user.following.each do |f|
  users.delete(f)
end

然后编译他们的帖子并排序:

posts = []
users.each do |u|
  posts += u.posts
end
posts.sort_by!{|x| x[:created_at]}.reverse!

我认为使用 Active Record 函数有更好的方法,但我不知道如何使它们与数组一起使用。例如,如果我编译一个 User id 值数组而不是完整模型,并尝试运行此代码以获取 post 数组:

posts = Post.where(
  user_id: user_ids
).order('created_at DESC').limit(21)

它返回一个空数组。有没有比我当前的解决方案更好的方法来搜索过滤器值数组?

更新:附加模态代码:

class Post < ActiveRecord::Base
  belongs_to :user
  ...

用户.rb

class User < ActiveRecord::Base
  has_many :photos
  has_many :active_relationships, class_name:  "Relationship",
                              foreign_key: "follower_id",
                              dependent:   :destroy
  has_many :passive_relationships, class_name:  "Relationship",
                               foreign_key: "followed_id",
                               dependent:   :destroy
  has_many :following, through: :active_relationships, source: :followed
  has_many :followers, through: :passive_relationships, source: :follower
  ...

【问题讨论】:

  • User has_many :followings, as: :follower, class_name: 'Relationship'吗?
  • 是的,我更新了更多的模态代码
  • 迭代 ActiveRecord 集合时,使用find_each 而不是eachfind_each 批量加载集合中的记录,而不是一次全部加载,这显然对您的内存加载更安全。

标签: ruby-on-rails arrays ruby activerecord


【解决方案1】:

您使用 user_ids 的想法很好。如果该查询返回一个空数组,那么您是否检查以确保 user_ids 是您所期望的?

至于代码,您需要查看Enumerable#map#flat_map。它们是内置的 ruby​​ 方法,用于完成您尝试使用 #each 循环执行的操作。您的代码可能会简化为:

user_ids = user.followings.flat_map { |following| following.following_id }
user_ids.uniq!
user_ids -= [user.id, user.following_ids].flatten
Post.where(user_id: user_ids).order(id: :desc).limit(21)

注意:由于 created_at 应该遵循 id 创建顺序,我会考虑基于 id 而不是 created_at 搜索,因为它应该有一个索引。

【讨论】:

    猜你喜欢
    • 2014-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-03
    • 2017-08-25
    • 2019-07-29
    • 2012-04-03
    • 2011-03-11
    相关资源
    最近更新 更多