Join us at MongoDB.local London on 7 May to unlock new possibilities for your data. Use WEB50 to save 50%.
Register now >
Docs Menu
Docs Home
/ /

Utilice tipos de campos BSON

En esta guía se pueden aprender los tipos de campo que son compatibles en Mongoid y que pueden usarse para definir el esquema de los documentos de MongoDB.

Usos de MongoDB Tipos BSON para representar los tipos de datos almacenados en los campos del documento. Para usar datos BSON en una aplicación Mongoid, Mongoid debe convertir los tipos BSON a tipos Ruby en tiempo de ejecución. Por ejemplo, al recuperar un documento de la base de datos, Mongoid traduce un BSON. double tipo para usar el tipo Ruby Float. Cuando guardas el documento nuevamente, Mongoid convierte el campo de nuevo a un BSON double.

Para aprender más sobre la modelación de documentos en Mongoid, consulte la Utilice el módulo de documentos en la guía de su modelo.

Nota

Modificar la definición del campo en una clase modelo no cambia ningún dato almacenado en la base de datos. Para cambiar el tipo de dato de un campo en la base de datos, debes guardar los datos nuevamente.

Puede definir nombres y tipos de campos en las clases de modelo mediante las macros field y type. El siguiente ejemplo define los campos de una clase Person:

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

La siguiente lista proporciona los tipos de campos que puedes usar en 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

Nota

Mongoid no admite BSON::Int64 ni BSON::Int32 como tipos de campos. Mongoid guarda correctamente estos valores en la base de datos, pero al recuperar los documentos, los campos se devuelven como tipos Integer.

De manera similar, al consultar campos con el tipo BSON::Decimal128, Mongoid devuelve los campos como tipos BigDecimal.

Si no se especifica un tipo para un campo, Mongoid lo interpreta como el tipo Object por defecto. Un campo sin tipo puede almacenar valores de cualquier tipo que sea directamente serializable a BSON. Se puede dejar un campo sin tipo si el campo puede contener diferentes tipos de datos o si no se conoce el tipo del valor del campo.

El siguiente ejemplo define una clase Product con un campo sin tipo:

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

El tipo del campo properties es Object pero varía dependiendo del tipo de datos almacenados en ese campo. El siguiente ejemplo guarda los datos en el campo properties de dos maneras diferentes:

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"}

Dado que Mongoid no realiza conversiones de tipo en campos sin tipo al leer de la base de datos, es posible que los valores que requieren un manejo especial no se recuperen correctamente como valor de un campo sin tipo. No almacene los siguientes tipos de datos BSON en campos sin tipo:

  • DateDevuelve como Time en campos no tipados

  • DateTimeDevuelve como Time en campos no tipados

  • RangeDevuelve como Hash en campos no tipados

Puede almacenar datos Hash en un campo usando el tipo Hash. Cuando se especifica un campo como Hash, asegúrese de seguir las restricciones de nomenclatura de MongoDB para asegurarse de que los valores se almacenen correctamente en la base de datos.

El siguiente ejemplo crea una clase Person y especifica el campo url como un Hash.

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

Puede almacenar valores como instancias BSON Time utilizando el valor del campo Time. Time los campos se almacenan en la zona horaria configurada para su aplicación. Para obtener más información sobre cómo configurar zonas horarias, consulta la sección Configuración de zona horaria de la guía Configuración de aplicación.

El siguiente ejemplo crea una clase Voter y especifica que el valor del campo registered_at es de tipo Time:

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

Nota

Almacenar un valor Date o DateTime en un campo especificado como Time convierte el valor en Time cuando se asigna. Si almacenas un string en un campo de Time, Mongoid analiza el string utilizando el método Time.parse. Para obtener más información sobre cómo Mongoid convierte las consultas, consulte la sección Conversiones de consultas de tipo de campo de la guía Especificar una consulta.

Puedes almacenar los siguientes tipos de valores en un campo especificado como un Date:

  • Date:Almacena el valor tal como se proporciona.

  • Time: Almacena la parte de la fecha del valor en la misma zona horaria de este.

  • DateTime: Almacena la parte de la fecha del valor en la misma zona horaria de este.

  • ActiveSupport::TimeWithZone: Almacena la parte de la fecha del valor en la misma zona horaria de este.

  • String: Almacena la fecha especificada en la string.

  • IntegerToma el valor como si fuera una marca de tiempo UTC y lo convierte a la zona horaria configurada de la aplicación. Mongoid almacena la fecha obtenida de esa marca de tiempo.

  • FloatToma el valor como si fuera una marca de tiempo UTC y lo convierte a la zona horaria configurada de la aplicación. Mongoid almacena la fecha obtenida de esa marca de tiempo.

Dado que convertir un Time o un DateTime descarta la porción de tiempo, recomendamos convertir explícitamente los objetos String, Time, y DateTime a Date antes de asignarlos al campo.

Nota

Cuando una base de datos contiene un valor de tipo "string" para un campo Date, el driver analiza el valor utilizando el método Time.parse y luego descarta la parte de tiempo. Time.parse considera que los valores sin zonas horarias están en la hora local. Para obtener más información sobre cómo Mongoid convierte las consultas, consulte la sección Conversiones de consultas de tipos de campo de la guía Especificar una consulta.

Cuando asignes un valor a un campo definido como DateTime o realices una query en estos campos, Mongoid convierte el valor a un valor UTC Time antes de enviarlo al servidor MongoDB. Mongoid guarda el valor con la zona horaria incrustada en el objeto DateTime. Cuando recuperas el valor, Mongoid convierte la hora UTC a la zona horaria configurada para tu aplicación.

El siguiente ejemplo crea una clase Ticket y especifica el campo purchased_at como un campo DateTime:

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

Si guardas un valor entero o flotante en un campo DateTime, el valor se trata como una marca de tiempo Unix en UTC. El siguiente ejemplo guarda un valor entero en el campo purchased_at:

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

Si se guarda un valor de string en un campo DateTime, Mongoid guarda el ticket con la zona horaria especificada. Si no se especifica una zona horaria, Mongoid guarda el valor usando la zona horaria configurada como por defecto para la aplicación:

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

Para obtener más información sobre cómo configurar las zonas horarias, consulta la sección Configuración de la zona horaria de la guía de configuración de la aplicación.

Nota

Mongoid analiza los valores de string en DateTime utilizando el método Time.parse, que considera que los valores sin zonas horarias están en la hora local.

Puedes incluir campos de marca de tiempo en una clase incluyendo el módulo Mongoid::Timestamps cuando crees tu clase. Cuando incluyes el Mongoid::Timestamps, Mongoid crea los siguientes campos en tu clase:

  • created_at: almacena la hora en que se creó el documento.

  • updated_at:Almacena la hora en que se actualizó el documento por última vez.

En el siguiente ejemplo se crea una clase Post con campos de marca de tiempo:

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

También puede optar por incluir solo los campos created_at o updated_at incluyendo solo los módulos Created o Updated. El siguiente ejemplo crea una clase Post con solo el campo created_at y una clase Post con solo el campo updated_at:

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

Puedes acortar los nombres de los campos de marcas de tiempo a c_at y u_at configurando la opción ::Short al incluir el módulo:

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

Puede deshabilitar la creación del campo de marca de tiempo para operaciones específicas llamando al método timeless en la llamada al método. El siguiente ejemplo deshabilita las marcas de tiempo para la operación save:

post.timeless.save

Puedes almacenar expresiones regulares en un campo usando el tipo Regexp.

Mientras MongoDB implementa expresiones regulares compatibles con Perl (PCRE), Mongoid utiliza la librería Onigmo de Ruby. PCRE y Onigmo ofrecen funcionalidades globalmente similares, pero hay varias diferencias de sintaxis. Por ejemplo, Onigmo utiliza \A y \z para hacer coincidir el principio y el final de una string, mientras que PCRE utiliza ^ y $.

Cuando declaras un campo como Regexp, Mongoid convierte las expresiones regulares de Ruby en expresiones regulares BSON al almacenar el resultado en tu base de datos. La base de datos devuelve el campo como una instancia de Bson::Regexp::Raw. Puedes usar el método compile en instancias de BSON::Regexp::Raw para convertir los datos de regreso a una expresión regular de Ruby.

La siguiente ejemplo crea una clase Token y especifica el campo pattern como 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">

Importante

Convertir una expresión regular BSON a una expresión regular Ruby podría producir una expresión regular diferente de la original. Esta diferencia se debe a las diferencias entre las sintaxis de Onigmo y PCRE. Para obtener más información sobre las expresiones regulares en Mongoid, consulta la sección de Expresiones regulares de la guía Especifica una query.

Puede usar el tipo BigDecimal para almacenar números con mayor precisión. Mongoid almacena valores BigDecimal de dos maneras diferentes, según el valor que configure para la propiedad de configuración Mongoid.map_big_decimal_to_decimal128:

  • Si se establece en true (predeterminado), Mongoid almacena valores BigDecimal como valores BSON Decimal128.

  • Si se establece en false, Mongoid almacena BigDecimal valores como cadenas.

Tenga en cuenta las siguientes limitaciones al establecer la opción Mongoid.map_big_decimal_to_decimal128 en true:

  • Decimal128 tiene un rango y una precisión limitados. Decimal128 tiene un valor máximo de aproximadamente 10^6145 y un mínimo de aproximadamente -10^6145, con un máximo de 34 bits de precisión. Si almacenas valores que están fuera de estos límites, recomendamos almacenarlos como cadenas de texto en su lugar.

  • Decimal128 acepta valores de NaN firmados, pero BigDecimal no los acepta. Recuperar los valores firmados NaN Decimal128 de la base de datos como BigDecimal devuelve el valor sin signo.

  • Decimal128 mantiene los ceros finales, pero BigDecimal no. Debido a esto, recuperar los valores Decimal128 de la base de datos como BigDecimal podría resultar en una pérdida de precisión.

Nota

Cuando configuras la opción Mongoid.map_big_decimal_to_decimal128 en false y almacenas un BigDecimal en un campo no tipado, no puedes consultar el campo como un BigDecimal. Debido a que el valor se almacena como un string, consultar el campo no tipado por un valor BigDecimal no encuentra el valor en la base de datos. Para encontrar el valor, primero debes convertir el valor de la query en una string.

Puede evitar este problema especificando el campo como un tipo BigDecimal, en lugar de como tipo sin tipar.

Use el tipo de campo StringifiedSymbol para almacenar valores que deben exponerse como símbolos para las aplicaciones Ruby. StringifiedSymbol te permite usar símbolos mientras garantiza la interoperabilidad con otros drivers. Este tipo almacena todos los datos en la base de datos como cadenas y convierte las cadenas en símbolos cuando son leídas por la aplicación. Los valores que no pueden convertirse directamente en símbolos, como enteros o arreglos, se convierten en cadenas y luego en símbolos.

El siguiente ejemplo define el campo status como StringifiedSymbol y demuestra cómo se almacena y se devuelve el campo:

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

Se pueden usar strings o símbolos para especificar ciertos tipos de campos en Mongoid, en vez de sus nombres de clase. El siguiente ejemplo especifica el campo order_num utilizando el nombre de la clase, un string y un símbolo:

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

La siguiente tabla proporciona los tipos de campos que puede especificar como cadenas o símbolos:

Nombre de la clase
Símbolo
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"

Puedes crear tipos de campos personalizados y definir cómo Mongoid los serializa y deserializa. Para crear un tipo de campo personalizado, definan una clase que implemente los siguientes métodos:

  • mongoize: Toma una instancia de tu tipo personalizado y la convierte en un objeto que MongoDB pueda almacenar.

  • demongoize:Toma un objeto de MongoDB y lo convierte en una instancia de su tipo personalizado.

  • evolve: Toma una instancia de tu tipo personalizado y la convierte en un criterio que MongoDB puede utilizar para query la base de datos.

El siguiente ejemplo crea un tipo de campo personalizado llamado Point e implementa los métodos anteriores:

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

En el ejemplo anterior, el mongoize método de instancia acepta una instancia de tu objeto de tipo personalizado y la convierte en un Array para almacenarlo en la base de datos. mongoize El método de clase acepta objetos de todo tipo y los convierte en tipos similares que pueden almacenarse en la base de datos. Mongoid utiliza el método de clase mongoize cuando llama a los métodos getter y setter.

El método demongoize convierte el valor Array almacenado en el tipo personalizado Point. Mongoid usa este método cuando llama al getter.

El método evolve convierte el tipo personalizado Point en un tipo consultable Array y convierte todos los demás tipos en object. Mongoid utiliza este método cuando llama a un método que consulta la base de datos.

Puede crear un tipo de campo personalizado que guarde en la base de datos un valor distinto al asignado en la aplicación. Esto puede ser útil para tener valores descriptivos en la aplicación y almacenar valores más compactos en la base de datos.

El siguiente ejemplo crea un tipo ColorMapping que utiliza el nombre del color en la aplicación, pero almacena el color como un entero en la base de datos:

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!

Puedes indicarle a Mongoid que cree campos dinámicamente incluyendo el módulo Mongoid::Attributes::Dynamic en tu modelo. Esto permite a Mongoid crear campos basándose en un hash arbitrario o en los documentos ya almacenados en la base de datos.

El siguiente ejemplo crea una clase Person con campos dinámicos:

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

Tip

Puedes especificar tanto campos fijos como campos dinámicos dentro de la misma clase. En este caso, Mongoid trata todos los atributos de las propiedades con definiciones de campo según su tipo de campo y todos los demás atributos como dinámicos.

Cuando utilices campos dinámicos en tu aplicación, debes establecer el valor inicialmente de una de las siguientes maneras:

  • Pasa el atributo hash al constructor.

  • Asigne valores usando el método attributes=.

  • Asigne valores usando el método []=.

  • Asigne valores usando el método write_attribute.

  • Trabajar con valores que ya están presentes en la base de datos.

Si no se establece inicialmente el valor usando una de las opciones anteriores, invocar el atributo devuelve un NoMethodError.

Tanto Mongoid como la API de query de MongoDB reservan el carácter . para separar nombres de campos en documentos anidados y el carácter $ al comienzo de una string para indicar un operador del query. Por este motivo, deberías evitar el uso de estos caracteres en los nombres de campos.

Si su aplicación requiere el uso de estos caracteres, puede acceder a los campos llamando al método send. El siguiente ejemplo crea una clase User con campos que contienen caracteres reservados. Luego accede a los campos mediante el método send:

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

También puedes acceder a estos campos llamando al método read_attribute.

Importante

Debido a que actualizar y reemplazar campos que contienen estos caracteres reservados requiere operadores especiales, llamar a getters y setters en estos campos genera una excepción InvalidDotDollarAssignment.

Volver

Comportamientos de campo

En esta página