MongoDB Mongoid 怎样做关联查询?

bindiry · February 09, 2012 · Last by lukefan replied at May 17, 2013 · 8525 hits

例如我有两张表:

  • brands 和 devices
  • brand has_many devices
  • devices belongs_to brand

我想在一个页面列出所有 brands,以及每个 brand 下面的 devices。

我现在的做法是先 @brands = Brand.all,然后通过循环取每个 brand 下面的 devices,就像下面这样:

@brands.each do |brand|
  brand.devices.each do |device|
    do something...
  end
end

但是看日志,每次 brand.devices.each 都会再去查询一次。

想请教一下,怎样做到关联查询,一次性把 brands 及下面的 devices 一起按结构层级取出来?

@brands = Brand.includes(:devices)

这样就可以了。

学习!

我才发现 mongoid 有 Eager load

#1 楼 @huacnlee 谢谢华顺指教。

@huacnlee 刚才试了一下@brands = Brand.includes(:devices),发现控制台输入的查询似乎是对的:

MONGODB demo_development['brands'].find({}).sort([[:name, :asc]])
MONGODB demo_development['devices'].find({"brand_id"=>{"$in"=>[BSON::ObjectId('4f03391e11aa2b1401000001'), BSON::ObjectId('4f03391e11aa2b1401000004'), BSON::ObjectId('4f03391e11aa2b1401000008'), BSON::ObjectId('4f03391e11aa2b1401000006')]}}).sort([["name", :asc]])

但是到我循环显示brand.devices.each的时候,还是会再去查询 devices:

MONGODB demo_development['brands'].find({}).sort([[:name, :asc]])
MONGODB demo_development['devices'].find({"brand_id"=>BSON::ObjectId('4f03391e11aa2b1401000001')}).sort([["name", :asc]])
MONGODB demo_development['devices'].find({"brand_id"=>BSON::ObjectId('4f03391e11aa2b1401000004')}).sort([["name", :asc]])
MONGODB demo_development['devices'].find({"brand_id"=>BSON::ObjectId('4f03391e11aa2b1401000008')}).sort([["name", :asc]])
MONGODB demo_development['devices'].find({"brand_id"=>BSON::ObjectId('4f03391e11aa2b1401000006')}).sort([["name", :asc]])

然后我用 rails console,输入Brand.includes(:devices).to_a,显示的也只有 brands 这一级内容,devices 没有显示。

是我哪里没搞正确吗?

#5 楼 @bindiry 官网上有写:

In order for #includes to work the Mongoid identity map must be enabled in the mongoid.yml:
identity_map_enabled: true

你看看是不是忘记设置这个

#6 楼 @HungYuHei 这个设置试过,没起作用。

哦,我搞错了,这个 has_many 的好像无法 includes 的 Mongoid 官方都有这种用法,不过现在 Ruby China 的“酷站”里面都不行 http://mongoid.org/docs/querying/criteria.html#includes

我再查查看

#9 楼 @huacnlee 谢谢,看官方文档有这么一句:This only works with has_many, has_one, and belongs_to relations and only 1 level deep at the current moment.

#10 楼 @bindiry

Person.includes(:posts, :game)

#11 楼 @huacnlee 那看起来会不会是个 bug?

@huacnlee @HungYuHei

问题解决了,我犯了个低级错误,把 identity_map_enabled: true 加到 development:外面去了。。。 加到 development:里就正常了。。。 掩面奔逃。。。

好吧,我是来围观的...

我搞了个 many_to_many 的,看来是没戏了。

#7 楼 @bindiry #11 楼 @huacnlee 如此例,如果需要用 brand 的 field 作为 where 里面的查询条件,来查询 devices 数据。怎么办呢?

#16 楼 @suxu 围观 学习了!如果我用 devices 的 created_at 来排序!我该如何做?

18 Floor has deleted

#17 楼 @tanjianna

查询 devices 数据。还是 brands 数据?

#19 楼 @suxu 查询 devices 数据

#20 楼 @tanjianna brand has_many devices

可以直接,brand.devices 啊。如果需要查询条件,跟上 where 即可

#22 楼 @lxyluu has_and_belongs_to_many :tags, inverse_of: nil doc 和 tag 之间,就是多对多的。 @articles = Article.desc(:updated_at).where(:tag_ids.in => [params[:tag_id]]) 这样查询。

@lukefan 多对多下,如果 params[:tag_id] 是一个 id 数组呢?就是 [1,2,3] 查询出同时有这个的 article!

#24 楼 @stephen 我没有做多标签选择,不过,搜集多个 id 应该是没有问题的吧。

You need to Sign in before reply, if you don't have an account, please Sign up first.