Mongoid has_many关系太慢(永无止境) - 40k文件

时间:2013-09-19 17:15:15

标签: ruby-on-rails ruby mongodb mongoid nosql

我有ClientGroup型号。客户有很多小组。

class Client
  include Mongoid::Document
  include Mongoid::Paranoia
  include Mongoid::Timestamps

  field ...

  has_many :groups, dependent: :delete

  ...
end

class Group
  ...

  belongs_to :client
end

一个客户有 40k 组,当我尝试client.groups时,需要的时间太长。我等了几分钟,它永远不会结束。

MONGODB (14.2ms) humtl_development['groups'].find({:deleted_at=>nil, "client_id"=>BSON::ObjectId('51b37763218c5a19e0000048')})
MONGODB [DEBUG] cursor.refresh() for cursor 48594378191047181

我在mongoid docs中找到了this

40k文件太多了吗?我应该摆脱has_many关系并使用embeds_many吗?问题是我的mongoid版本? MongoDB配置?任何建议都表示赞赏。

当然,我不需要显示所有40k组,我需要的是User.where(:group_id.in => client.groups.map(&:id))

非常感谢。

PS: MongoDB v2.4.3 mongoid v2.7.1 mongo v1.9.2

1 个答案:

答案 0 :(得分:2)

确保您的文档已编入client_id索引,因此查找速度很快。那么您可以使用distinct(:_id)在数组中获取40K ID。所以您的最终查询将如下所示:User.where(:group_id.in => client.groups.distinct(:_id))。这是我能想到的最有效的方法来获得40K ID的数组。尝试一下 - 它可能会奏效,但正如大家所说的那样 - 它不是网络规模;)

从我所看到的,您正在尝试获取给定客户端的所有用户,并且您的用户可能通过不同的组与多个客户端相关联。为了能够有效地为没有连接的客户端查找用户(因为您没有加入mongoid),您可以在没有反向关系的客户端上使用HABTM。所以我会这样做:

class Client
  include Mongoid::Document
  include Mongoid::Paranoia
  include Mongoid::Timestamps

  field ...

  has_and_belongs_to_many :users
  has_many :groups, dependent: :delete

  ...
end

class User
  has_and_belongs_to_many :clients
end

然后,每次将用户与群组关联时,请务必将群组的客户端添加到用户(user.clients << clientclient.users << user),以便彼此了解。不要担心重复,因为mongoid正在使用Set,所以如果用户和客户端之间的关系已经存在,它就不会做任何事情。然后,您可以从客户端查找用户:client.users或查找多个客户的用户:User.where(:client_ids.in => client_ids)