Rails + Mongoid - Don't Return Nil Values in JSON

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

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-routes

More 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



Leave a reply



Submit