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 fieldsx=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 tooto 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 Have to_json return a mongoid as a string
You can monkey patch Moped::BSON::ObjectId
:
module Moped
module BSON
class ObjectId
def to_json(*)
to_s.to_json
end
def as_json(*)
to_s.as_json
end
end
end
end
to take care of the $oid
stuff and then Mongoid::Document
to convert _id
to id
:module Mongoid
module Document
def serializable_hash(options = nil)
h = super(options)
h['id'] = h.delete('_id') if(h.has_key?('_id'))
h
end
end
end
That will make all of your Mongoid objects behave sensibly. Calling .attributes on model object avoid fileds with nil values
mongoid
used to remove empty fields. If you kept some fields empty on insert, mongoid
will removes them.
Use media.to_json
instead for your case.
mongoid: Rails says field exists, mongodb says contrary
Don't rely on the ActiveRecord adaptation in Mongoid; use the aggregation pipeline. This will (to the best of my knowledge) always return correct results since it simply pushes the argument hash into mongo.
The aggregation pipeline at first seems unintuitive to use, but after you get to know how to use it it is a very powerful tool if you want to make complex queries. The Rails syntax is as follows:
MyClassName.collection.aggregate( <array> )
where the <array>
contains hashes, each of which is a command used on the result of the execution of the preceding hash. The documentation can be found at https://docs.mongodb.com/manual/aggregation/.To convert the commands there to Ruby it is only required to surround the entries by quotes.
To give an example: The following is the mongo syntax:
db.orders.aggregate([
{ $match: { status: "A" } },
{ $group: { _id: "$cust_id", total: { $sum: "$amount" } } }
])
This takes all documents from the orders
collection and selects all those where the status field matches "A" (the word $match
left of the colon is a mongo command). Those then get grouped ($group
) by the cust_id
field and the sum ($sum
) of the contents of the amount
field is computed.If you want to convert this to Ruby, you change it into
Orders.collection.aggregate([
{ '$match': {'status': 'A'}},
{ '$group': {'_id': '$cust_id', 'total': {'$sum': '$amount'}}}
])
This worked for me, and what's even better is that it takes significantly less time than using Orders.where(...) in Rails and doing the computation in Rails.The trade-off is that you don't get returned Ruby objects but hashes of arrays of hashes.
find() with nil when there are no records
Yes, just do:
Challenge.find_by_id(10)
For Rails 4 and 5:Challenge.find_by(id: 10)
Rails Mongoid includes doesn't load child models
To display genres
for each of all available books
:
def show
books = Book.all
render json: books, include: :genres
end
To display genres
for a particular book
:def show
book = Book.find(params[:id])
render json: book, include: :genres
end
Rails, Mongoid, query: Not returns documents
You're looking in the wrong places. The error is saying there's something wrong with your config/routes.rb
file. Rails is not being able to figure out what URL matches the show
method in your controller.
Apparently rails generate scaffold_controller
does not edit the routes.rb
, so you'll have to do it by hand and add the following code to it:
resources :tipocontenidos
There's a great tool to debug Rails routing here: http://guides.rubyonrails.org/routing.html#listing-existing-routesMore about routing: http://guides.rubyonrails.org/routing.html
Exclude fields from document in mongoid?
You don't want to remove fields from the mongoid document, what you want to do is remove fields from the generated json.
In your controller, do
render :json => @model.to_json(:except => :_id)
Documentation for the to_json method http://apidock.com/rails/ActiveRecord/Serialization/to_json Rails can't render JSON undefined method `new' for nil:NilClass
I just realised I forgot to generate the serializer. Since I use gem Active Model Serializers, this is what I did to generate the serializer.
rails g serializer facility
Related Topics
Ruby 1.9 How to Convert Array to String Without Brackets
Automatically Adding Proxy to All Http Connections in Ruby
How to Scrape a Website with The Socksify Gem (Proxy)
How to Directly Install a Gem from a Git Repository
Ruby: How to Convert an Array of Data to Hash and to JSON Format
Will_Paginate Find Out If I'M on The Last Page
How to Run Capybara-Webkit (I.E. Forked Webkit_Server) on Heroku Cedar
Where Are Keywords Defined in Ruby
How to Access a Toplevel Entity in Ruby, from Inside a Module Which Defines The Same Name
Use Pry in Gems Without Modifying The Gemfile or Using 'Require'
Pod Install in Xcode Bots Trigger
Getting a "Connection Reset by Peer" Error When Hitting Google Contacts API
How to Get Meta Keywords Using Nokogiri
Why Should @@Class_Variables Be Avoided in Ruby
How to Test If a Value Is a Prime Number in Ruby? Both The Easy and The Hard Way
Understanding The Behaviour of Inject Used with a Lambda in Ruby