fields
Even though MongoDB is a schemaless database, most uses will be with web applications where form parameters always come to the server as strings. Mongoid provides an easy mechanism for transforming these strings into their appropriate types through the definition of fields in a Mongoid::Document.
Consider a simple class for modeling a person in an application. A person may have a first name, last name, and middle name. We can define these attributes on a person by using the fields macro.
class Person include Mongoid::Document field :first_name, type: String field :middle_name, type: String field :last_name, type: String end
Below is a list of valid types for fields.
- Array
- BigDecimal (Stores as a String in the database)
- Boolean
- Date
- DateTime
- Float
- Hash
- Integer
- Range
- String
- Symbol
- Time
If you decide not to specify the type of field with the definition, Mongoid will treat it as an object and not try to typecast it when sending the values to the database. This can be advantageous in 2 places, since the lack of attempted conversion will yield a slight performance gain. However some fields are not supported if not defined as fields. A note of thumb for what fields you can use are:
- You're not using a web front end and values are already properly cast.
- All of your fields are strings.
class Person include Mongoid::Document field :first_name field :middle_name field :last_name end
Types that are not supported as dynamic attributes since they cannot be cast are:
- BigDecimal
- Date
- DateTime
- Range
getting and setting field values
When a field is defined, Mongoid provides several different ways of accessing the field.
# Get the value of the first name field. person.first_name person[:first_name] person.read_attribute(:first_name) # Set the value for the first name field. person.first_name = "Jean" person[:first_name] = "Jean" person.write_attribute(:first_name, "Jean")
In cases where you want to set multiple field values at once, there are a few different ways of handling this as well.
# Get the field values as a hash. person.attributes # Set the field values in the document. Person.new(first_name: "Jean-Baptiste", middle_name: "Emmanuel") person.attributes = { first_name: "Jean-Baptiste", middle_name: "Emmanuel" } person.write_attributes( first_name: "Jean-Baptiste", middle_name: "Emmanuel" )
defaults
You can tell a field in Mongoid to always have a default value if nothing has been provided. Defaults are either static values or lambdas.
class Person include Mongoid::Document field :blood_alcohol_level, type: Float, default: 0.40 field :last_drink, type: Time, default: -> { 10.minutes.ago } end
Be wary that default values that are not defined as lambdas or procs are evaluated at class load time, so the following 2 definitions are not equivalent. (You probably would prefer the second, which is at document creation time.)
field :dob, type: Time, default: Time.now field :dob, type: Time, default: -> { Time.now }
If you want to set a default with a dependency on the document's state, self inside a lambda or proc evaluates to the document instance.
field :wasted_at, type: Time, default: -> { new? ? 2.hours.ago : Time.now }
custom field serialization
You can define custom types in Mongoid and determine how they are serialized and deserialized. You simply need to define the class, include Mongoid::Fields::Serializable, and override the serialize and deserialize methods as needed. Deserialization is used to convert from the value that is stored in the database to a value that is used when accessed. Serialization is used to convert the object to a MongoDB friendly value.
class Profile include Mongoid::Document field :location, type: Point end class Point include Mongoid::Fields::Serializable def deserialize(object) [ object["x"], object["y"] ] end def serialize(object) { "x" => object[0], "y" => object[1] } end end
reserved names
If you define a field on your document that conflicts with a reserved method name in Mongoid, the configuration will raise an error. For a list of these you may look at Mongoid.destructive_fields.