Rails + Mongoid - Don't return nil values in JSON
By default mongoid
has the ability to remove empty fields. If you let some fields empty, mongoid
will removes them on insert.
in the below example, I left out the fields element & rect
class User
include Mongoid::Document
field :key, type: String
field :element, type: String
field :rect, type: Array
embeds_one :home
end
>> u=User.new(:key=>'ram').to_json
=> "{"_id":"4f1c3722b356f82e4a000001","_type":"key":"ram"}"
and it works perfectly. But if you put a nil value in the field
>> u=User.new(:key=>'ram',:element=>nil).to_json
=> "{"_id":"4f1c3722b356f82e4a000001","_type":"User","key":"ram","element":null}"
It gets inserted. I assume that's the exact problem in your code. So you can work around this by converting JSON hash representation using as_json
and remove the nil fields
x=u.as_json.reject! {|k,v| v.nil?}
=> "{"_id":"4f1c3722b356f82e4a000001","_type":"User","key":"ram"}"
But to go to the inner levels, you cannot use as_json
. check the below code
>>h=Home.new(:address=>'xxxx',:dummy=>nil)
>>u.home = h
>>x=u.as_json.reject! {|k,v| v.nil?}
=>{"_id"=>BSON::ObjectId('4f1c39b4b356f82e4a000003'), "_type"=>"User","key":"ram","home"=>#<Home _id: 4f1c3c5db356f82e4a000004,address:'xxxx' , dummy: nil >}
Now you see the field dummy inside the embedded doc house is still with nil. so my best advice is Dont put the nil values in db at all. To do that put a before_save
callback on your models (embedded too) and remove the empty fields.
Also I will show you how to remove nil fields from nested objects too. Use it if there is no other way
We can use attributes
of mongoid model to get the hash representation of the object including the nested levels
x=u.attributes
=> {"_id"=>BSON::ObjectId4f1c39b4b356f82e4a000003,"key"=>"ram","element"=>nil,"home"=>{"address"=>"xxxx", "_id"=>BSON::ObjectId4f1c3c5db356f82e4a000004,"dummy"=>nil}}
and you have to find is there any Hash inside the mongoid object, if one, we have to use the reject! {|k,v| v.nil?}
on that Hash too
to put together all
def to_json(obj)
obj.reject! {|k,v| v.nil?}
obj.find_all {|x| x[1].class==BSON::OrderedHash}.each do |arr|
obj[arr[0]] = to_json(arr[1])
end
obj
end
and call this with attributes of the model,
>> to_json u.attributes
=> {"_id"=>BSON::ObjectId4f1c39b4b356f82e4a000003,"key"=>"ram","home"=>{"address"=>"xxxx", "_id"=>BSON::ObjectId4f1c3c5db356f82e4a000004}}
Thats all. Hope it helps
If you are just trying to remove field keys with nil values from query results before sending JSON, say, to the browser, you can simply do this (works in my case):
doc = Model.all.entries.map {|d| d.as_document}
respond_width(doc)