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.