Docs Menu
Docs Home
/ / /
Mongoid
/

Field Types

On this page

  • Overview
  • Field Types
  • Untyped Fields
  • Hash
  • Time
  • Date
  • DateTime
  • Timestamps
  • Regexp
  • BigDecimal
  • StringifiedSymbol
  • Specify Field Types as Strings or Symbols
  • Custom Field Types
  • Phantom Custom Field Types
  • Dynamic Fields
  • Reserved Characters

In this guide, you can learn about the field types supported in Mongoid that you can use to define the schema for your MongoDB documents.

MongoDB uses BSON types to represent the data types stored in document fields. To use BSON data in a Mongoid application, Mongoid must convert the BSON types to Ruby types at runtime. For example, when retrieving a document from the database, Mongoid translates a BSON double type to use the Ruby Float type. When you save the document again, Mongoid converts the field back to a BSON double.

To learn more about modeling documents in Mongoid, see the Documents guide.

Note

Modifying the field definition in a model class does not change any data stored in the database. To change the data type of a field in the database, you must re-save the data again.

You can define field names and types in model classes by using the field and type macros. The following example defines the fields of a Person class:

class Person
include Mongoid::Document
field :name, type: String
field :date_of_birth, type: Date
field :weight, type: Float
end

The following list provides the field types that you can use in Mongoid:

  • Array

  • Bson::Binary

  • BigDecimal

  • Mongoid::Boolean or Boolean

  • Date

  • DateTime

  • Float

  • Hash

  • Integer

  • Object

  • Bson::ObjectId

  • Range

  • Regexp

  • Set

  • String

  • Mongoid::StringifiedSymbol

  • Time

  • ActiveSupport::TimeWithZone

Note

Mongoid does not support BSON::Int64 or BSON::Int32 as field types. Mongoid saves these values to the database correctly, but when you retrieve the documents, the fields are returned as Integer types.

Similarly, when querying fields with the BSON::Decimal128 type, Mongoid returns the fields as BigDecimal types.

If you don't specify a type for a field, Mongoid interprets it as the default Object type. An untyped field can store values of any type that is directly serializable to BSON. You can leave a field untyped if the field might contain different types of data, or if the type of the field's value is not known.

The following example defines a Product class with an untyped field:

class Product
include Mongoid::Document
field :name, type: String
field :properties
end

The type of the properties field is Object but varies depending on the type of data stored in that field. The following example saves data into the properties field in two different ways:

product = Product.new(properties: "color=white,size=large")
# properties field saved as String: "color=white,size=large"
product = Product.new(properties: {color: "white", size: "large"})
# properties field saved as Object: {:color=>"white", :size=>"large"}

Because Mongoid doesn't perform any type conversions on untyped fields when reading from the database, values that require special handling might not be retrieved correctly in as the value of an untyped field. Do not store the following BSON data types in untyped fields:

  • Date: Returns as Time in untyped fields

  • DateTime: Returns as Time in untyped fields

  • Range: Returns as Hash in untyped fields

You can store Hash data in a field by using the Hash type. When you specify a field as a Hash, ensure that you follow the MongoDB Naming Restrictions to ensure that the values store properly in the database.

The following example creates a Person class and specifies the url field as a Hash.

class Person
include Mongoid::Document
field :first_name
field :url, type: Hash
end
person = Person.new(url: {'home_page' => 'http://www.homepage.com'})

You can store values as BSON Time instances by using the Time field value. Time fields are stored in the time zone configured for your application. To learn more about configuring time zones, see the Time Zone Configuration section of the Application Configuration guide.

The following example creates a Voter class and specifies that the value of the registered_at field is a Time type:

class Voter
include Mongoid::Document
field :registered_at, type: Time
end
Voter.new(registered_at: Date.today)

Note

Storing a Date or DateTime value in a field specified as Time converts the value to Time when assigned. If you store a string in a Time field, Mongoid parses the string by using the Time.parse method. To learn more about how Mongoid converts queries, see the Field Type Query Conversions section of the Specify a Query guide.

You can store the following value types in a field specified as a Date:

  • Date: Stores the value as provided.

  • Time: Stores the date portion of the value in the value's time zone.

  • DateTime: Stores the date portion of the value in the value's time zone.

  • ActiveSupport::TimeWithZone: Stores the date portion of the value in the value's time zone.

  • String: Stores the date specified in the string.

  • Integer: Takes the value as if it is a UTC timestamp and converts it into your application's configured time zone. Mongoid then stores the date taken from that timestamp.

  • Float: Takes the value as if it is a UTC timestamp and converts it into your application's configured time zone. Mongoid then stores the date taken from that timestamp.

Because converting a Time or DateTime discards the time portion, we recommend explicitly converting String, Time, and DateTime, objects to Date before assigning them to the field.

Note

When a database contains a string value for a Date field, the driver parses the value by using the Time.parse method, then discards the time portion. Time.parse considers values without time zones to be in local time. To learn more about how Mongoid converts queries, see the Field Type Query Conversions section of the Specify a Query guide.

When you assign a value to a field defined as a DateTime or query on these fields, Mongoid converts the value to a UTC Time value before sending it to the MongoDB server. Mongoid saves the value with the time zone embedded in the DateTime object. When you retrieve the value, Mongoid converts the UTC time to the time zone configured for your application.

The following example creates a Ticket class and specifies the purchased_at field as a DateTime field:

class Ticket
include Mongoid::Document
field :purchased_at, type: DateTime
end

If you save an integer or float value to a DateTime field, the value is treated as a Unix timestamp in UTC. The following example saves an integer value to the purchased_at field:

ticket.purchased_at = 1544803974
ticket.purchased_at
# Outputs: Fri, 14 Dec 2018 16:12:54 +0000

If you save a string value to a DateTime field, Mongoid saves the ticket with the time zone specified. If a time zone is not specified, Mongoid saves the value by using the timezone configured as the default for your application:

ticket.purchased_at = 'Mar 4, 2018 10:00:00 +01:00'
ticket.purchased_at
# Outputs: Sun, 04 Mar 2018 09:00:00 +0000

To learn more about configuring time zones, see the Time Zone Configuration section of the Application Configuration guide.

Note

Mongoid parses string values into DateTime by using the Time.parse method, which considers values without time zones to be in local time.

You can include timestamp fields in a class by including the Mongoid::Timestamps module when you create your class. When you include the Mongoid::Timestamps, Mongoid creates the following fields in your class:

  • created_at: Stores the time the document was created.

  • updated_at: Stores the time the document was last updated.

The following example creates a Post class with timestamp fields:

class Post
include Mongoid::Document
include Mongoid::Timestamps
end

You can also choose to include only the created_at or updated_at fields by including only the Created or Updated modules. The following example creates a Post class with only the created_at field, and a Post class with only the updated_at field:

class Post
include Mongoid::Document
include Mongoid::Timestamps::Created
end
class Post
include Mongoid::Document
include Mongoid::Timestamps::Updated
end

You can shorten the timestamp field names to c_at and u_at by setting the ::Short option when including the module:

class Post
include Mongoid::Document
include Mongoid::Timestamps::Short # For c_at and u_at.
end
class Post
include Mongoid::Document
include Mongoid::Timestamps::Created::Short # For c_at only.
end
class Post
include Mongoid::Document
include Mongoid::Timestamps::Updated::Short # For u_at only.
end

You can disable creating the timestamp field for specific operations by calling the timeless method on the method call. The following example disables the timestamps for the save operation:

post.timeless.save

You can store regular expressions in a field by using the Regexp type.

While MongoDB implements Perl Compatible Regular Expressions (PCRE), Mongoid uses Ruby's Onigmo library. PCRE and Onigmo provide generally similar functionality, but there are several syntax differences. For example, Onigmo uses \A and \z to match the beginning and end of a string, while PCRE uses ^ and $.

When you declare a field as a Regexp, Mongoid converts Ruby regular expressions to BSON regular expressions when storing the result into your database. The database returns the field as a Bson::Regexp::Raw instance. You can use the compile method on BSON::Regexp::Raw instances to convert the data back to a Ruby regular expression.

The following example creates a Token class and specifies the pattern field as a Regexp:

class Token
include Mongoid::Document
field :pattern, type: Regexp
end
token = Token.create!(pattern: /hello.world/m)
token.pattern
# Outputs: /hello.world/m
# Reload the token from the database
token.reload
token.pattern
# Outputs: #<BSON::Regexp::Raw:0x0000555f505e4a20 @pattern="hello.world", @options="ms">

Important

Converting a BSON regular expression to a Ruby regular expression might produce a different regular expression than the original. This difference is due to the differences between the Onigmo and PCRE syntaxes. To learn more about regular expressions in Mongoid, see the Regular Expressions section of the Specify a Query guide.

You can use the BigDecimal type to store numbers with increased precision. Mongoid stores BigDecimal values in two different ways, depending on the value you set for the Mongoid.map_big_decimal_to_decimal128 configuration property:

  • If set to true, Mongoid stores BigDecimal values as BSON Decimal128 values.

  • If set to false (default), Mongoid stores BigDecimal values as strings.

Consider the following limitations when setting the Mongoid.map_big_decimal_to_decimal128 option to true:

  • Decimal128 has a limited range and precision. Decimal128 has a maximum value of approximately 10^6145 and a minimum of approximately -10^6145, with a maximum of 34 bits of precision. If you are storing values that are outside of these limits, we recommend storing them as strings instead.

  • Decimal128 accepts signed NaN values, but BigDecimal does not. Retrieving signed NaN Decimal128 values from the database as BigDecimal returns the value unsigned.

  • Decimal128 maintains trailing zeroes, but BigDecimal does not. Because of this, retrieving Decimal128 values from the database as BigDecimal might result in a loss of precision.

Note

When you set the Mongoid.map_big_decimal_to_decimal128 option to false and store a BigDecimal into an untyped field, you cannot query the field as a BigDecimal. Because the value is stored as a string, querying the untyped field for a BigDecimal value does not find the value in the database. To find the value, you must first convert the query value to a string.

You can avoid this issue by specifying the field as a BigDecimal type, instead of as untyped.

Use the StringifiedSymbol field type to store values that should be exposed as symbols to Ruby applications. StringifiedSymbol allows you to use symbols while ensuring interoperability with other drivers. This type stores all data on the database as strings, and converts the strings to symbols when read by the application. Values that cannot be directly converted to symbols, such as integers and arrays, are converted into strings and then into symbols.

The following example defines the status field as a StringifiedSymbol and demonstrates how the field is stored and returned:

class Post
include Mongoid::Document
field :status, type: StringifiedSymbol
end
# Save status as a symbol
post = Post.new(status: :hello)
# status is stored as "hello" on the database, but returned as a Symbol
post.status
# Outputs: :hello
# Save status as a string
post = Post.new(status: "hello")
# status is stored as "hello" in the database, but returned as a Symbol
post.status
# Outputs: :hello

You can use strings or symbols to specify certain field types in Mongoid, instead of using their class names. The following example specifies the order_num field by using the class name, a string, and a symbol:

class Order
include Mongoid::Document
# Class Name
field :order_num, type: Integer
# Symbol
field :order_num, type: :integer
# String
field :order_num, type: "integer"
end

The following table provides the field types that can you can specify as strings or symbols:

Class Name
Symbol
String

Array

:array

"Array"

BigDecimal

:big_decimal

"BigDecimal"

BSON::Binary

:binary

"BSON::Binary"

Mongoid::Boolean

:boolean

"Mongoid::Boolean"

Date

:date

"Date"

DateTime

:date_time

"DateTime"

Float

:float

"Float"

Hash

:hash

"Hash"

Integer

:integer

"Integer"

BSON::ObjectId

:object_id

"BSON::ObjectId"

Range

:range

"Range"

Regexp

:regexp

"Regexp"

Set

:set

"Set"

String

:string

"String"

StringifiedSymbol

:stringified_symbol

"StringifiedSymbol"

Symbol

:symbol

"Symbol"

Time

:time

"Time"

You can create custom field types and define how Mongoid serializes and deserializes them. To create a custom field type, define a class that implements the following methods:

  • mongoize: Takes an instance of your custom type and converts it to an object that MongoDB can store.

  • demongoize: Takes an object from MongoDB and converts it to an instance of your custom type.

  • evolve: Takes an instance of your custom type and converts it to a criteria that MongoDB can use to query the database.

The following example creates a custom field type called Point and implements the preceding methods:

class Point
attr_reader :x, :y
def initialize(x, y)
@x, @y = x, y
end
# Converts an object of this instance into an array
def mongoize
[ x, y ]
end
class << self
# Takes any possible object and converts it to how it is
# stored in the database.
def mongoize(object)
case object
when Point then object.mongoize
when Hash then Point.new(object[:x], object[:y]).mongoize
else object
end
end
# Gets the object as it's stored in the database and instantiates
# this custom class from it.
def demongoize(object)
if object.is_a?(Array) && object.length == 2
Point.new(object[0], object[1])
end
end
# Converts the object supplied to a criteria and converts it
# into a queryable form.
def evolve(object)
case object
when Point then object.mongoize
else object
end
end
end
end

In the preceding example, the mongoize instance method accepts an instance of your custom type object and converts it to an Array to store in the database. The mongoize class method accepts objects of all types and converts them to similar types that can be stored in the database. Mongoid uses the mongoize class method when it calls the getter and setter methods.

The demongoize method converts the stored Array value into the custom Point type. The Mongoid uses this method when it calls the getter.

The evolve method converts the custom Point type into a queryable Array type, and converts all other types to object. Mongoid uses this method when it calls a method that queries the database.

You can create a custom field type that saves a different value to the database than the value assigned in the application. This can be useful to have descriptive values in the application while storing more compact values in the database.

The following example creates a ColorMapping type that uses the name of the color in the application, but stores the color as an integer in the database:

class ColorMapping
MAPPING = {
'black' => 0,
'white' => 1,
}.freeze
INVERSE_MAPPING = MAPPING.invert.freeze
class << self
def mongoize(object)
MAPPING[object]
end
def demongoize(object)
INVERSE_MAPPING[object]
end
def evolve(object)
MAPPING.fetch(object, object)
end
end
end
class Profile
include Mongoid::Document
field :color, type: ColorMapping
end
profile = Profile.new(color: 'white')
profile.color
# Outputs: "white"
# Sets "color" field to 0 in MongoDB
profile.save!

You can instruct Mongoid to create fields dynamically by including the Mongoid::Attributes::Dynamic module in your model. This allows Mongoid to create fields based on an arbitrary hash, or based on the documents already stored in the database.

The following example creates a Person class with dynamic fields:

class Person
include Mongoid::Document
include Mongoid::Attributes::Dynamic
end

Tip

You can specify both fixed fields and dynamic fields within the same class. In this case, Mongoid treats all attributes for properties with field definitions according to their field type, and all other attributes as dynamic.

When using dynamic fields in your application, you must initially set the value in one of the following ways:

  • Pass the attribute hash to the constructor.

  • Assign values by using the attributes= method.

  • Assign values by using the []= method.

  • Assign values by using the write_attribute method.

  • Work with values that are already present in the database.

If you don't initially set the value by using one of the preceding options, invoking the attribute returns a NoMethodError.

Both Mongoid and the MongoDB Query API reserve the . character to separate field names in nested documents and the $ character at the beginning of a string to indicate a query operator. Because of this, you should avoid using these characters in your field names.

If your application requires the use of these characters, you can access the fields by calling the send method. The following example creates a User class with fields that contain reserved characters. It then accesses the fields by using the send method:

class User
include Mongoid::Document
field :"first.last", type: String
field :"$_amount", type: Integer
end
user = User.first
user.send(:"first.last")
# Outputs: Mike.Trout
user.send(:"$_amount")
# Outputs: 42650000

You can also access these fields by calling the read_attribute method.

Important

Because updating and replacing fields containing these reserved characters requires special operators, calling getters and setters on these fields raises an InvalidDotDollarAssignment exception.

Back

Documents