In Rails, Using Mongoid, How do I find all Models with a valid (not nil) has_one reference?
Asked Answered
W

3

8

So I have a two models like this

class ModelParent
  include Mongoid::Document
  field :name, :type => String
  has_one :model_child
end

class ModelChild
  include Mongoid::Document
  field :name, :type => String
  belongs_to :model_parent
end

Assuming I have an persisted instance of ModelParent called mp in the rails console

mc = mp.create_model_child(:name=>"child")

and then do

mp.model_child

it returns a valid object

however if I search for it like this:

ModelParent.where(:model_child.ne => nil).length

it returns 0

I've tried creating model_child and then assigning it, also using build_model_child(), and each method shows model_child is clearly in the parent, however the query for not nil (.ne) fails to find all ModelParents with children.

What am I doing wrong?

Update:

Answering my own question. I'm still unsure why the :model_child.ne => nil is not working, however...

I solved the problem by coding something like this:

  def self.with_child
    user_ids = ModelChild.all.only(:model_parent_id).map(&:model_parent_id)
    return ModelParent.where(:_id.in => user_ids).all
  end
Womble answered 8/4, 2012 at 22:39 Comment(0)
M
8

It is not working as foreign key is stored on belongs to side of the relationship. So, in your case ModelChild collection will have a field model_parent_id and not the other way around. I guess you had already figured that out, but instead of solving it the way you did, I would suggest you switch around the has_one and belongs_to associations and then use:

 ModelParent.where(:model_child_id.ne => nil)
Monda answered 9/4, 2012 at 10:15 Comment(0)
G
1

I found another way, but I don't know if is more efficient or less: you can use the reject method. For example:

ModelParent.all.reject{ |r| r.model_child.nil?}
Gynous answered 12/5, 2014 at 12:37 Comment(0)
E
0

I wouldn't rely on the .ne in such cases, I found that .ne method isn't always working good: For example try to put a string named "false" and try to search for it with .ne ;-)

I found out that for such cases the best way to find the proper models reliably is to filter by native Mongo $type

ModelParent.where(:model_child_id => { :$type => 7 })

Below the list of known types, found this much more efficient to find malformed fields

  • Double 1
  • String 2
  • Object 3
  • Array 4
  • Binary data 5
  • Undefined (deprecated) 6
  • Object id 7
  • Boolean 8
  • Date 9
  • Null 10
  • Regular Expression 11
  • JavaScript 13
  • Symbol 14
  • JavaScript (with scope) 15
  • 32-bit integer 16
  • Timestamp 17
  • 64-bit integer 18
  • Min key 255
  • Max key 127
Escharotic answered 12/3, 2014 at 22:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.