Docs Menu
Docs Home
/ /

Formato de datos BSON

En esta guía, puede aprender sobre el formato de datos BSON, cómo MongoDB usa BSON para organizar y almacenar datos y cómo instalar la biblioteca BSON independientemente del controlador Ruby.

BSON, o JSON binario, es el formato de datos que MongoDB utiliza para organizar y almacenar datos. Este formato incluye todos los tipos de estructuras de datos JSON y admite tipos como fechas, enteros de diferentes tamaños (bits32de y 64bit de), ObjectIds y datos binarios. Para obtener una lista completa de los tipos admitidos, consulte Tipos BSON en la documentación del servidor MongoDB.

BSON no es legible, pero puedes usar la biblioteca Ruby BSON para convertirlo a la representación JSON legible. Puedes leer más sobre la relación entre estos formatos en la guía JSON y BSON del sitio web de MongoDB.

Puede instalar la biblioteca BSON (bson) de Rubygems manualmente o usando el empaquetador.

Ejecute el siguiente comando para instalar la gema bson:

gem install bson

Para instalar la gema usando bundler, incluya la siguiente línea en el Gemfile de su aplicación:

gem 'bson'

La biblioteca BSON es compatible con MRI v2.5 y posteriores y JRuby v9.2 y posteriores.

La serialización de las clases definidas en Soporte Activo, como TimeWithZone, no se carga de forma predeterminada para evitar una fuerte dependencia de BSON con Soporte Activo. Al usar BSON en una aplicación que también usa Soporte Activo, debe requerir la compatibilidad del código de Soporte Activo:

require 'bson'
require 'bson/active_support'

Puede recuperar la representación BSON sin procesar de un objeto Ruby llamando a to_bson en el objeto. El método to_bson devuelve un BSON::ByteBuffer.

El siguiente código demuestra cómo llamar al método to_bson en objetos Ruby:

"Shall I compare thee to a summer's day".to_bson
1024.to_bson

Puede generar un objeto Ruby a partir de BSON llamando a from_bson en la clase que desea instanciar y pasándole una instancia BSON::ByteBuffer:

String.from_bson(byte_buffer)
BSON::Int32.from_bson(byte_buffer)

bson v4.0 introduce el uso de buffers de bytes nativos en MRI y JRuby en lugar de usar StringIO para mejorar el rendimiento.

Para crear un ByteBuffer para escribir, instancia un BSON::ByteBuffer sin argumentos:

buffer = BSON::ByteBuffer.new

Para escribir bytes sin procesar en el búfer de bytes sin transformaciones, utilice los métodos put_byte y put_bytes. Cada método toma una cadena de bytes como argumento y la copia en el búfer. El método put_byte exige que el argumento sea una cadena de longitud 1. put_bytes acepta cadenas de cualquier longitud. Las cadenas pueden contener bytes nulos.

El siguiente código demuestra cómo escribir bytes sin procesar en un búfer de bytes:

buffer.put_byte("\x00")
buffer.put_bytes("\xff\xfe\x00\xfd")

Nota

put_byte y put_bytes no escriben un byte de tipo BSON en el búfer antes de escribir la cadena de bytes. Esto significa que el búfer no contiene información sobre el tipo de datos que codifica la cadena de bytes sin procesar.

Los métodos de escritura descritos en las siguientes secciones escriben objetos de tipos específicos en la especificación BSON. El tipo indicado por el nombre del método prevalece sobre el tipo del argumento. Por ejemplo, si se pasa un valor de punto put_int32 flotante a, se convierte a un entero y el controlador escribe el entero resultante en el búfer de bytes.

Para escribir una cadena UTF-8 (tipo BSON 0x02) en el búfer de bytes, utilice el método put_string:

buffer.put_string("hello, world")

Las cadenas BSON siempre se codifican en UTF-8. Esto significa que el argumento de put_string debe estar en UTF-8 o en una codificación convertible a UTF-8 (no binaria). Si el argumento está en una codificación distinta a UTF-8, la cadena se convierte primero a UTF-8 y, a continuación, se escribe en el búfer la versión codificada en UTF-8. La cadena debe ser válida en su codificación especificada. Puede contener bytes nulos.

La especificación BSON también define un tipo CString, que se utiliza, por ejemplo, para claves de documentos. Para guardar CStrings en el buffer, utiliza put_cstring:

buffer.put_cstring("hello, world")

Al igual que con las cadenas regulares, las CStrings en BSON deben estar codificadas en UTF-8. Si el argumento no se encuentra en UTF-8, será convertido a UTF-8 y la string resultante se escribirá en el buffer. A diferencia de put_string, la codificación UTF-8 del argumento proporcionado a put_cstring no puede contener ningún byte nulo, ya que el formato de serialización CString en BSON está terminado en nulo.

A diferencia de put_string, put_cstring también acepta símbolos y enteros. En todos los casos, el argumento se convierte en cadena antes de ser escrito en el búfer:

buffer.put_cstring(:hello)
buffer.put_cstring(42)

Para escribir un entero de 32o 64bits en el búfer de bytes, utilice los métodos put_int32 y put_int64, respectivamente. Tenga en cuenta que los enteros de Ruby pueden ser arbitrariamente grandes; si el valor que se escribe excede el rango de un entero de 32o 64bits, put_int32 y put_int64 generan un error RangeError.

El siguiente código demuestra cómo escribir valores enteros en un búfer de bytes:

buffer.put_int32(12345)
buffer.put_int64(123456789012345)

Nota

Si se dan argumentos de punto flotante a put_int32 o put_int64, los argumentos primero se convierten en números enteros y los números enteros se escriben en el búfer de bytes.

Para escribir un valor de punto flotante de 64bits en el búfer de bytes, utilice put_double:

buffer.put_double(3.14159)

Para recuperar los datos serializados como una cadena de bytes, llama a to_s en el buffer:

buffer = BSON::ByteBuffer.new
buffer.put_string('testing')
socket.write(buffer.to_s)

Nota

ByteBuffer Registra las posiciones de lectura y escritura por separado. No es posible rebobinar el búfer para escribir. El método rewind solo afecta la posición de lectura.

Para crear un ByteBuffer para leer o deserializar desde BSON, cree una instancia de BSON::ByteBuffer con una cadena de bytes como argumento:

buffer = BSON::ByteBuffer.new(string)

Puede leer desde el búfer utilizando los siguientes métodos que corresponden a diferentes tipos de datos:

buffer.get_byte # Pulls a single byte from the buffer
buffer.get_bytes(value) # Pulls n number of bytes from the buffer
buffer.get_cstring # Pulls a null-terminated string from the buffer
buffer.get_double # Pulls a 64-bit floating point from the buffer
buffer.get_int32 # Pulls a 32-bit integer (4 bytes) from the buffer
buffer.get_int64 # Pulls a 64-bit integer (8 bytes) from the buffer
buffer.get_string # Pulls a UTF-8 string from the buffer

Para reiniciar la lectura desde el principio de un búfer, utilice rewind:

buffer.rewind

Nota

ByteBuffer Realiza un seguimiento de las posiciones de lectura y escritura por separado. El método rewind solo afecta la posición de lectura.

La siguiente lista proporciona las clases Ruby que tienen representaciones en la especificación BSON y tienen un método to_bson definido:

  • Object

  • Array

  • FalseClass

  • Float

  • Hash

  • Integer

  • BigDecimal

  • NilClass

  • Regexp

  • String

  • Symbol (deprecated)

  • Time

  • TrueClass

Además de los objetos principales de Ruby, BSON también proporciona algunos tipos especiales específicos de la especificación. Las siguientes secciones describen otros tipos compatibles con el controlador.

Utilice objetos BSON::Binary para almacenar datos binarios arbitrarios. Puede construir objetos Binary a partir de cadenas binarias, como se muestra en el siguiente código:

BSON::Binary.new("binary_string")
# => <BSON::Binary:0x47113101192900 type=generic data=0x62696e6172795f73...>

De forma predeterminada, los objetos Binary se crean con el subtipo binario BSON 0 (:generic). Puede especificar explícitamente el subtipo para indicar que los bytes codifican un tipo de datos específico:

BSON::Binary.new("binary_string", :user)
# => <BSON::Binary:0x47113101225420 type=user data=0x62696e6172795f73...>

La siguiente lista proporciona las especificaciones de subtipos válidas:

  • :generic

  • :function

  • :old

  • :uuid_old

  • :uuid

  • :md5

  • :ciphertext

  • :column

  • :sensitive

  • :vector

  • :user

Puede utilizar los atributos data y type para recuperar los datos y el subtipo de un objeto Binary, como se muestra en el siguiente código:

binary = BSON::Binary.new("binary_string", :user)
binary.data
# => "binary_string"
binary.type
# => :user

Puede comparar Binary objetos con el <=> operador, que permite ordenar objetos con el mismo subtipo binario. Para comparar Binary objetos, asegúrese de instalar5.0.2 la versión 7100 o posterior de la biblioteca BSON.

Nota

Codificación BINARIA

BSON::Binary Los objetos siempre almacenan los datos en codificación BINARY, independientemente de la codificación de la cadena pasada al constructor:

str = "binary_string"
str.encoding
# => #<Encoding:US-ASCII>
binary = BSON::Binary.new(str)
binary.data
# => "binary_string"
binary.data.encoding
# => #<Encoding:ASCII-8BIT>

Para crear un UUID BSON::Binary (subtipo binario 4) a partir de su representación de cadena compatible con RFC 4122, utilice el método from_uuid:

uuid_str = "00112233-4455-6677-8899-aabbccddeeff"
BSON::Binary.from_uuid(uuid_str)
# => <BSON::Binary:0x46986653612880 type=uuid data=0x0011223344556677...>

Para convertir un UUID BSON::Binary en una representación compatible con RFC 4122, utilice el método to_uuid:

binary = BSON::Binary.new("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF".force_encoding('BINARY'), :uuid)
# => <BSON::Binary:0x46942046606480 type=uuid data=0x0011223344556677...>
binary.to_uuid
# => "00112233-4455-6677-8899aabbccddeeff"

Puede especificar explícitamente la representación UUID estándar en los métodos from_uuid y to_uuid:

binary = BSON::Binary.from_uuid(uuid_str, :standard)
binary.to_uuid(:standard)

Puede utilizar la representación :standard solo con un valor Binary del subtipo :uuid, no :uuid_old.

Los datos almacenados en objetos BSON::Binary de subtipo 3 (:uuid_old) pueden persistirse en alguno de los tres diferentes órdenes de bytes, dependiendo del controlador que los creó. Los órdenes de bytes son heredado de CSharp, heredado de Java y heredado de Python. El orden de bytes heredado de Python es el mismo que el orden de bytes estándar de la RFC 4122. Los órdenes de bytes heredados de CSharp y Java tienen algunos bytes en ubicaciones diferentes.

El Binary objeto que contiene un UUID heredado no codifica el formato en el que se almacena dicho UUID. Por lo tanto, los métodos que convierten al formato UUID heredado y viceversa toman el formato o representación deseado como argumento. Una aplicación puede copiar Binary objetos UUID heredados sin saber en qué orden de bytes almacenan sus datos.

Los siguientes métodos para trabajar con UUID heredados se proporcionan para la interoperabilidad con implementaciones existentes que almacenan datos en formatos UUID heredados. En aplicaciones nuevas, utilice únicamente el formato :uuid (subtipo 4), que cumple con la RFC 4122.

Para convertir un UUID heredado BSON::Binary en una cadena, utilice el método to_uuid y especifique la representación deseada. Las representaciones aceptadas son :csharp_legacy, :java_legacy y :python_legacy. Un UUID heredado BSON::Binary no se puede convertir en una cadena sin especificar una representación.

binary = BSON::Binary.new("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF".force_encoding('BINARY'), :uuid_old)
# => <BSON::Binary:0x46942046606480 type=uuid data=0x0011223344556677...>
binary.to_uuid
# => ArgumentError (Representation must be specified for BSON::Binary objects of type :uuid_old)
binary.to_uuid(:csharp_legacy)
# => "33221100-5544-7766-8899aabbccddeeff"
binary.to_uuid(:java_legacy)
# => "77665544-3322-1100-ffeeddccbbaa9988"
binary.to_uuid(:python_legacy)
# => "00112233-4455-6677-8899aabbccddeeff"

Para crear un UUID heredado BSON::Binary a partir de la representación de cadena del UUID, utilice el método from_uuid y especifique la representación deseada:

uuid_str = "00112233-4455-6677-8899-aabbccddeeff"
BSON::Binary.from_uuid(uuid_str, :csharp_legacy)
# => <BSON::Binary:0x46986653650480 type=uuid_old data=0x3322110055447766...>
BSON::Binary.from_uuid(uuid_str, :java_legacy)
# => <BSON::Binary:0x46986653663960 type=uuid_old data=0x7766554433221100...>
BSON::Binary.from_uuid(uuid_str, :python_legacy)
# => <BSON::Binary:0x46986653686300 type=uuid_old data=0x0011223344556677...>

Puede utilizar estos métodos para convertir de una representación a otra:

BSON::Binary.from_uuid('77665544-3322-1100-ffeeddccbbaa9988',:java_legacy).to_uuid(:csharp_legacy)
# => "33221100-5544-7766-8899aabbccddeeff"

A partir de bson v5.1, puede utilizar el tipo BSON::Vector para representar vectores de valores numéricos.

Puede crear un objeto BSON::Vector para almacenar valores de los siguientes tipos:

  • int8

  • float32

  • packed_bit

Puede utilizar los atributos opcionales dtype y padding para especificar el tipo de datos del vector y el relleno de bits, respectivamente. BSON::Vector en sí es un contenedor para guardar los valores de la matriz, la información de tipo y la especificación de relleno. Los objetos BSON::Vector se serializan como matrices normales en MongoDB.

El siguiente ejemplo demuestra cómo crear un objeto BSON::Vector:

BSON::Vector.new([ -0.0016261312, -0.028070757, -0.011342932 ], :float32)

Puede convertir BSON::Vector objetos y array en objetos BSON::Binary para que se serialicen como instancias de vector binario BSON 9 (subtipo). Utilice el BSON::Binary.from_vector método, como se muestra en el siguiente código:

vector = BSON::Vector.new([ -0.0016261312, -0.028070757, -0.011342932 ], :float32)
BSON::Binary.from_vector(vector)

El uso del BSON::Binary tipo mejora la eficiencia del almacenamiento. Para obtener más información, consulte la especificación BSON.

Puedes convertir un BSON::Binary en un BSON::Vector utilizando el método BSON::Binary.as_vector.

Tip

Búsqueda vectorial de MongoDB

Para ver un ejemplo que aprovecha el tipo BSON::Binary para realizar consultas de búsqueda vectorial de MongoDB eficientes, consulte Ejemplos de consultas de búsqueda de MongoDB.

Este tipo representa una cadena de código JavaScript:

BSON::Code.new("this.value = 5;")

Esta es una subclase de BSON::Document que proporciona accesores para la colección, el identificador y la base de datos de DBRef.

BSON::DBRef.new({"$ref" => "collection", "$id" => "id"})
BSON::DBRef.new({"$ref" => "collection", "$id" => "id", "database" => "db"})

Nota

El constructor BSON::DBRef valida el hash dado y genera un ArgumentError si no es un DBRef válido. Los métodos BSON::ExtJSON.parse_obj y Hash.from_bson no generan un error si se pasa un DBRef no válido y, en su lugar, analizan un Hash o deserializan un BSON::Document.

Nota

Todos los documentos BSON se deserializan en instancias de BSON::DBRef si son instancias válidas de DBRef; de lo contrario, se deserializan en instancias de BSON::Document. Esto se cumple incluso cuando la invocación se realiza desde la clase Hash:

bson = {"$ref" => "collection", "$id" => "id"}.to_bson.to_s
loaded = Hash.from_bson(BSON::ByteBuffer.new(bson))
=> {"$ref"=>"collection", "$id"=>"id"}
loaded.class
=> BSON::DBRef

BSON::Document es una subclase de Hash que almacena todas las claves como cadenas, pero permite el acceso a ellas mediante claves de símbolos.

BSON::Document[:key, "value"]
BSON::Document.new

Nota

Todos los documentos BSON se deserializan en instancias de BSON::Document o BSON::DBRef, si son instancias válidas de DBRef, incluso cuando la invocación se realiza desde la clase Hash:

bson = {test: 1}.to_bson.to_s
loaded = Hash.from_bson(BSON::ByteBuffer.new(bson))
# => {"test"=>1}
loaded.class
# => BSON::Document

BSON::MaxKey representa un valor en BSON que siempre se compara con un valor mayor que cualquier otro valor:

BSON::MaxKey.new

BSON::MinKey representa un valor en BSON que siempre se compara con un valor inferior a cualquier otro valor:

BSON::MinKey.new

BSON::ObjectId representa un identificador único de 12 bytes para un objeto:

BSON::ObjectId.new

BSON::Timestamp representa un tiempo con un valor de inicio y de incremento:

BSON::Timestamp.new(5, 30)

BSON::Undefined representa un marcador de posición para un valor que no está definido:

BSON::Undefined.new

BSON::Decimal128 representa un valor de punto flotante basado en decimales de 128bits que puede emular el redondeo decimal con precisión exacta:

# Instantiate with a String
BSON::Decimal128.new("1.28")
# Instantiate with a BigDecimal
d = BigDecimal(1.28, 3)
BSON::Decimal128.new(d)

Los métodos BigDecimal#from_bson y BigDecimal#to_bson utilizan internamente los métodos equivalentes BSON::Decimal128. Esto conlleva ciertas limitaciones en los valores BigDecimal que se pueden serializar a BSON y en aquellos que se pueden deserializar a partir de valores BSON decimal128 existentes.

Serializar instancias BigDecimal como instancias BSON::Decimal128 ofrece mayor flexibilidad al realizar consultas y agregaciones en MongoDB. La siguiente lista describe las limitaciones de BigDecimal:

  • Decimal128 tiene un rango y precisión limitados, mientras que BigDecimal no tiene restricciones en términos de rango y precisión. Decimal128 tiene un valor máximo de aproximadamente 10^6145 y un valor mínimo de aproximadamente -10^6145, y tiene un máximo de 34 bits de precisión.

  • Decimal128 Puede aceptar valores con signo NaN, mientras que BigDecimal no. Todos los valores con signo NaN que se deserializan en instancias BigDecimal no estarán firmados.

  • Decimal128 mantiene los ceros finales al serializar y deserializar desde BSON. BigDecimal, sin embargo, no mantiene los ceros finales y, por lo tanto, el uso de BigDecimal puede generar una falta de precisión.

Nota

En la librería BSON v5.0, Decimal128 se deserializa en BigDecimal por defecto. Para que los valores de Decimal128 en los documentos BSON se deserialicen en BSON::Decimal128, se puede establecer la opción mode: :bson al llamar a from_bson.

Algunos tipos BSON tienen representaciones especiales en JSON. La siguiente tabla describe el comportamiento de serialización de los tipos especificados al llamar a to_json en ellos.

Objeto BSON de Ruby
Representación JSON

BSON::Binary

{ "$binary" : "\x01", "$type" : "md5" }

BSON::Code

{ "$code" : "this.v = 5" }

BSON::CodeWithScope

{ "$code" : "this.v = value", "$scope" : { v => 5 }}

BSON::DBRef

{ "$ref" : "collection", "$id" : { "$oid" : "id" }, "$db" : "database" }

BSON::MaxKey

{ "$maxKey" : 1 }

BSON::MinKey

{ "$minKey" : 1 }

BSON::ObjectId

{ "$oid" : "4e4d66343b39b68407000001" }

BSON::Timestamp

{ "t" : 5, "i" : 30 }

Regexp

{ "$regex" : "[abc]", "$options" : "i" }

Los tiempos en Ruby tienen una precisión de nanosegundos. Los tiempos en BSON tienen una precisión de milisegundos. Al serializar instancias de Ruby Time en BSON o JSON extendido, los tiempos se redondean al milisegundo más cercano.

Nota

Los valores de tiempo se redondean a la baja. Si la hora es anterior a la época Unix (enero 1, 1970 00:00:00 UTC), el valor absoluto de la hora aumenta:

time = Time.utc(1960, 1, 1, 0, 0, 0, 999_999)
time.to_f
# => -315619199.000001
time.floor(3).to_f
# => -315619199.001

Debido a este comportamiento de redondeo, recomendamos que realice todos los cálculos de tiempo utilizando matemáticas enteras, ya que la inexactitud de los cálculos de punto flotante puede producir resultados inesperados.

Nota

JRuby 9.2.11.0 redondea los tiempos de época pre-Unix hacia arriba en lugar de hacia abajo. Para obtener más información sobre este comportamiento, consulte el problema de GitHub relacionado. La biblioteca BSON corrige este comportamiento y reduce los tiempos al serializar en JRuby.

BSON permite almacenar valores de tiempo como el número de segundos transcurridos desde la época de Unix. Las instancias de Ruby DateTime se pueden serializar en BSON, pero al deserializarse, los tiempos se devolverán como instancias Time.

La clase DateTime en Ruby soporta calendarios no gregorianos. Cuando las instancias DateTime no-gregorianas son serializadas, primero se convierten al calendario gregoriano, y la fecha respectiva en el calendario gregoriano se almacena en la base de datos.

BSON permite almacenar valores de tiempo como el número de segundos transcurridos desde la época de Unix. Las instancias de Ruby Date se pueden serializar en BSON, pero al deserializarse, los tiempos se devolverán como instancias Time.

Cuando se serializan instancias Date, el valor de tiempo utilizado es la medianoche del Date en UTC.

Tanto MongoDB como Ruby ofrecen compatibilidad con expresiones regulares, pero utilizan motores de expresiones regulares. Las siguientes subsecciones detallan las diferencias entre las expresiones regulares de Ruby y las de MongoDB.

MongoDB utiliza expresiones regulares compatibles con Perl implementadas mediante la biblioteca PCRE.Las expresiones regulares de Ruby se implementan mediante el motor de expresiones regulares Onigmo, una bifurcación de la biblioteca Oniguruma.

Las dos implementaciones de expresiones regulares, generalmente, proporcionan una funcionalidad equivalente, pero tienen varias diferencias de sintaxis importantes, que se describen en las siguientes secciones.

No existe una manera sencilla de convertir programáticamente una expresión regular PCRE en la expresión regular Ruby equivalente, ya que actualmente no existen enlaces Ruby para PCRE.

Tanto las expresiones regulares de Ruby como las de PCRE admiten modificadores. Estos también se denominan "opciones" en Ruby y "indicadores" en PCRE. El significado de los modificadores s y m difiere en Ruby y PCRE de las siguientes maneras:

  • Ruby no tiene el modificador s. En su lugar, el modificador m de Ruby realiza la misma función que el modificador s de PCRE: hacer que el punto (.) coincida con cualquier carácter, incluyendo los saltos de línea. La documentación de Ruby menciona el modificador m como habilitador del modo multilínea.

  • Ruby siempre opera en el equivalente del modo multilínea de PCRE, habilitado por el modificador m en las expresiones regulares de PCRE. En Ruby, el ancla ^ siempre se refiere al principio de la línea y el ancla $ siempre se refiere al final de la línea.

Al escribir expresiones regulares destinadas a entornos Ruby y PCRE, incluyendo MongoDB Server y la mayoría de los demás controladores de MongoDB, evite usar los anclajes ^ y $. Las siguientes secciones ofrecen soluciones alternativas y recomendaciones para crear expresiones regulares portables que puedan usarse en múltiples contextos.

En las expresiones regulares de Ruby, el ancla ^ siempre se refiere al principio de la línea. En las expresiones regulares de PCRE, el ancla ^ se refiere al principio de la entrada por defecto, y el indicador m cambia su significado al principio de la línea.

Tanto las expresiones regulares de Ruby como las de PCRE admiten el ancla \A para referirse al principio de la entrada, independientemente de los modificadores. Las siguientes sugerencias permiten escribir expresiones regulares portátiles:

  • Utilice el ancla \A para hacer referencia al comienzo de la entrada.

  • Utilice el ancla ^ para referirse al inicio de la línea si activa el indicador m en expresiones regulares de PCRE. Como alternativa, utilice una de las siguientes construcciones, que funcionan independientemente de los modificadores:

    • (?:\A|(?<=\n)): maneja los finales de línea LF y CR+LF

    • (?:\A|(?<=[\r\n])): maneja los finales de línea CR, LF y CR+LF

En las expresiones regulares de Ruby, el ancla $ siempre se refiere al final de la línea. En las expresiones regulares de PCRE, el ancla $ se refiere al final de la entrada por defecto y el indicador m cambia su significado a fin de línea.

Tanto las expresiones regulares de Ruby como de PCRE admiten el ancla \z para hacer referencia al final de la entrada, independientemente de los modificadores.

Las siguientes sugerencias le permiten escribir expresiones regulares portables:

  • Utilice el ancla \z para hacer referencia al final de la entrada.

  • Utilice el ancla $ para referirse al inicio de la línea si activa el indicador m en expresiones regulares de PCRE. Como alternativa, utilice una de las siguientes construcciones, que funcionan independientemente de los modificadores:

    • (?:\z|(?=\n)): maneja los finales de línea LF y CR+LF

    • (?:\z|(?=[\n\n])): maneja los finales de línea CR, LF y CR+LF

Dado que no existe una forma sencilla de convertir programáticamente una expresión regular PCRE en la expresión regular Ruby equivalente, la librería BSON proporciona la clase BSON::Regexp::Raw para almacenar expresiones regulares PCRE.

Puede crear instancias BSON::Regexp::Raw utilizando la expresión regular text como una cadena y modificadores PCRE opcionales:

BSON::Regexp::Raw.new("^b403158")
# => #<BSON::Regexp::Raw:0x000055df63186d78 @pattern="^b403158", @options="">
BSON::Regexp::Raw.new("^Hello.world$", "s")
# => #<BSON::Regexp::Raw:0x000055df6317f028 @pattern="^Hello.world$", @options="s">

El módulo BSON::Regexp está incluido en la clase Ruby Regexp, de modo que se puede omitir el prefijo BSON:::

Regexp::Raw.new("^b403158")
# => #<BSON::Regexp::Raw:0x000055df63186d78 @pattern="^b403158", @options="">
Regexp::Raw.new("^Hello.world$", "s")
# => #<BSON::Regexp::Raw:0x000055df6317f028 @pattern="^Hello.world$", @options="s">

El siguiente código convierte una expresión regular de Ruby en una instancia BSON::Regexp::Raw:

regexp = /^Hello.world/
bson_regexp = BSON::Regexp::Raw.new(regexp.source, regexp.options)
# => #<BSON::Regexp::Raw:0x000055df62e42d60 @pattern="^Hello.world", @options=0>

El constructor BSON::Regexp::Raw acepta tanto las opciones numéricas de Ruby como las cadenas modificadoras PCRE.

Para convertir una expresión regular BSON en una expresión regular Ruby, llame al método compile en la expresión regular BSON:

bson_regexp = BSON::Regexp::Raw.new("^hello.world", "s")
bson_regexp.compile
# => /^hello.world/m
bson_regexp = BSON::Regexp::Raw.new("^hello.world", "")
bson_regexp.compile
# => /^hello.world/
bson_regexp = BSON::Regexp::Raw.new("^hello.world", "m")
bson_regexp.compile
# => /^hello.world/

El modificador PCRE s se convirtió al modificador Ruby m en el primer ejemplo del código anterior, y los dos últimos ejemplos se convirtieron a la misma expresión regular aunque las expresiones regulares BSON originales tenían significados diferentes.

Cuando una expresión regular BSON utiliza los anclajes no portables ^ y $, su conversión a una expresión regular de Ruby puede cambiar su significado:

BSON::Regexp::Raw.new("^hello.world", "").compile =~ "42\nhello world"
# => 3

Cuando una expresión regular de Ruby se convierte en una expresión regular BSON, por ejemplo, como parte de una consulta, la expresión regular BSON siempre tiene el modificador m establecido, lo que refleja el comportamiento de los anclajes ^ y $ en las expresiones regulares de Ruby.

Tanto las expresiones regulares Ruby como BSON implementan el método to_bson para serializar en BSON:

regexp_ruby = /^b403158/
# => /^b403158/
regexp_ruby.to_bson
# => #<BSON::ByteBuffer:0x007fcf20ab8028>
_.to_s
# => "^b403158\x00m\x00"
regexp_raw = Regexp::Raw.new("^b403158")
# => #<BSON::Regexp::Raw:0x007fcf21808f98 @pattern="^b403158", @options="">
regexp_raw.to_bson
# => #<BSON::ByteBuffer:0x007fcf213622f0>
_.to_s
# => "^b403158\x00\x00"

Las clases Regexp y BSON::Regexp::Raw implementan el método de la clase from_bson, que deserializa una expresión regular de un búfer de bytes BSON. Los métodos de ambas clases devuelven una instancia BSON::Regexp::Raw que debe convertirse en una expresión regular de Ruby mediante el método compile, como se describe en el código anterior.

El siguiente código demuestra cómo utilizar el método from_bson para deserializar una expresión regular:

byte_buffer = BSON::ByteBuffer.new("^b403158\x00\x00")
regex = Regexp.from_bson(byte_buffer)
# => #<BSON::Regexp::Raw:0x000055df63100d40 @pattern="^b403158", @options="">
regex.pattern
# => "^b403158"
regex.options
# => ""
regex.compile
# => /^b403158/

Los documentos BSON conservan el orden de las claves, ya que se almacenan como listas de pares clave-valor. Los hashes en Ruby también conservan el orden de las claves, por lo que el orden de las claves especificadas en la aplicación se conserva al serializar un hash en un documento BSON y al deserializar un documento BSON en un hash.

La especificación BSON permite que los documentos BSON tengan claves duplicadas, ya que se almacenan como listas de pares clave-valor. Evite crear documentos que contengan claves duplicadas, ya que el comportamiento de MongoDB Server no está definido cuando un documento BSON contiene claves duplicadas.

En Ruby, los hashes no pueden tener claves duplicadas. Al serializar hashes de Ruby en documentos BSON, no se generan claves duplicadas.

Dado que las claves en los documentos BSON siempre se almacenan como cadenas, especificar la misma clave como cadena y un símbolo en Ruby conserva solo la especificación más reciente:

BSON::Document.new(test: 1, 'test' => 2)
# => {"test"=>2}

Al cargar un documento BSON con claves duplicadas, el último valor de una clave duplicada sobrescribe los valores anteriores de la misma clave.

Volver

Agregación