Overview
En esta guía, puedes aprender sobre el formato de datos BSON, cómo MongoDB utiliza BSON para organizar y almacenar datos, y cómo instalar la librería BSON de forma independiente del driver de Ruby.
Formato de datos BSON
BSON, o JSON binario, es el formato de datos que MongoDB usa para organizar y almacenar datos. Este formato de datos incluye todos los tipos de estructuras de datos JSON y añade soporte para tipos como fechas, números enteros de diferente tamaño (32bits y 64bits), ObjectId y datos binarios. Para ver una lista completa de los tipos compatibles, consulta la BSON types en la documentación del MongoDB Server.
BSON no es legible por humanos, pero puedes usar la librería BSON de Ruby para convertirlo en la representación JSON legible por humanos. Puedes leer más sobre la relación entre estos formatos en la guía JSON y BSON en el sitio web de MongoDB.
Instalar la librería BSON
Puede instalar la biblioteca BSON (bson) de Rubygems manualmente o utilizando el bundler.
Ejecuta el siguiente comando para instalar la gema bson:
gem install bson
Para instalar la gem usando bundler, incluye la siguiente línea en tu Gemfile de la aplicación:
gem 'bson'
La biblioteca BSON es compatible con MRI v2.5 y posteriores y JRuby v9.2 y posteriores.
ActiveSupport
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'
Serialización BSON
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
Puedes generar un objeto Ruby a partir de BSON llamando a from_bson en la clase que deseas instanciar y pasándole una instancia de BSON::ByteBuffer:
String.from_bson(byte_buffer) BSON::Int32.from_bson(byte_buffer)
Buffers de bytes
bson v4.0 introduce el uso de buffers de bytes nativos en MRI y JRuby en lugar de utilizar StringIO para mejorar el rendimiento.
Guardar en un búfer de bytes
Para crear un ByteBuffer para la escritura, instancia un BSON::ByteBuffer sin argumentos:
buffer = BSON::ByteBuffer.new
Bytes crudos
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 guardar 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 guardes un byte de tipo BSON en el búfer antes de guardar la string de bytes. Esto significa que el buffer no tiene información sobre el tipo de datos que la string de bytes sin procesar codifica.
Métodos de escritura de bytes tipificados
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.
Strings
Para escribir una string UTF-8 (tipo BSON 0x02) en el búfer de bytes, utiliza 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 de UTF-8, la string se convierte primero a UTF-8 y luego, la versión codificada en UTF-8 se escribe en el búfer. La string debe ser válida en la codificación que se indica. La string 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)
Números
Para guardar un entero de 32bits o de 64bits en el búfer de bytes, usa los métodos put_int32 y put_int64, respectivamente. Ten en cuenta que los enteros Ruby pueden ser arbitrariamente grandes; si el valor que se escribe excede el rango de un entero de 32bits o de 64bits, put_int32 y put_int64 lanzan un error RangeError.
El siguiente código demuestra cómo se pueden guardar valores enteros en un búfer de bytes:
buffer.put_int32(12345) buffer.put_int64(123456789012345)
Nota
Si a put_int32 o put_int64 se les proporcionan argumentos de punto flotante, primero se fuerzan los argumentos a enteros y los enteros se escriben en el búfer de bytes.
Para guardar un valor de punto flotante de 64 bits en el búfer de bytes, utiliza put_double:
buffer.put_double(3.14159)
Convertir bytes en cadenas
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 rastrea las posiciones de lectura y escritura por separado. No existe una manera de rebobinar el búfer para escribir. El método rewind solo afecta a la posición de lectura.
Leer desde un Byte Buffer
Para crear un ByteBuffer para lectura o deserialización desde BSON, instancia BSON::ByteBuffer con una string 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 comienzo de un búfer, se usa rewind:
buffer.rewind
Nota
ByteBuffer rastrea las posiciones de lectura y escritura por separado. El método rewind afecta solo la posición de lectura.
Clases admitidas
La siguiente lista proporciona las clases Ruby que tienen representaciones en la especificación BSON y tienen un método to_bson definido:
ObjectArrayFalseClassFloatHashIntegerBigDecimalNilClassRegexpStringSymbol(deprecated)TimeTrueClass
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.
BSON::Binario
Utiliza objetos BSON::Binary para almacenar datos binarios arbitrarios. Puedes 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...>
Por defecto, los objetos Binary se crean con el subtipo binario BSON 0 (:generic). Puedes especificar explícitamente el subtipo para indicar que los bytes codifican un tipo particular de datos:
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 usar los atributos data y type para recuperar los datos de un objeto Binary y su subtipo, como se muestra en el siguiente código:
binary = BSON::Binary.new("binary_string", :user) binary.data # => "binary_string" binary.type # => :user
Puedes comparar Binary objetos usando el operador <=>, que permite ordenar objetos que tengan el mismo subtipo binario. Para comparar Binary objetos, asegúrese de instalar la versión5.0.2 o posterior de la librería BSON.
Nota
Codificación BINARY
BSON::Binary Los objetos siempre almacenan los datos en codificación BINARY, independientemente de la codificación de la string 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>
Métodos UUID
Para crear un UUID BSON::Binary (subtipo binario 4) a partir de su representación string compatible con RFC 4122, utiliza 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"
Puedes especificar explícitamente la representación estándar de UUID 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.
UUIDs heredados
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 objeto Binary que contiene un UUID heredado no codifica en qué formato se almacena el UUID. Por lo tanto, los métodos que convierten hacia y desde el formato UUID heredado toman el formato deseado, o representación, como su argumento. Una aplicación puede copiar objetos UUID heredados Binary 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 serializar un UUID heredado BSON::Binary, utiliza el método to_uuid y especifica la representación deseada. Las representaciones aceptadas son :csharp_legacy, :java_legacy y :python_legacy. Un UUID heredado BSON::Binary no puede convertirse a texto 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"
BSON::Vector
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:
int8float32packed_bit
Puedes 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í mismo es un contenedor para almacenar los valores de tu arreglo, la información de tipo y la especificación de relleno. BSON::Vector objetos se serializan como arreglos normales en MongoDB.
El siguiente ejemplo demuestra cómo crear un objeto BSON::Vector:
BSON::Vector.new([ -0.0016261312, -0.028070757, -0.011342932 ], :float32)
Convertir vectores a binario
Puede convertir BSON::Vector y objetos de arreglo a objetos BSON::Binary para que se serialicen como instancias binarias de vector BSON (subtipo 9). Utiliza el método BSON::Binary.from_vector, 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 utiliza el tipo BSON::Binary para realizar eficientes MongoDB Vector Search, consulte el Ejemplos de consultas de búsqueda de MongoDB.
BSON::codigo
Este tipo representa una string de código JavaScript:
BSON::Code.new("this.value = 5;")
BSON::DBRef
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 es cierto 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::Documento
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
BSON::MaxKey representa un valor en BSON que siempre se compara como superior a cualquier otro valor:
BSON::MaxKey.new
BSON::MinKey
BSON::MinKey representa un valor en BSON que siempre se compara como más bajo que cualquier otro valor:
BSON::MinKey.new
BSON::Id. de objeto
BSON::ObjectId representa un identificador único de objeto de 12 bytes:
BSON::ObjectId.new
BSON::Timestamp
BSON::Timestamp representa un tiempo con un valor de inicio y de incremento:
BSON::Timestamp.new(5, 30)
BSON::Undefined
BSON::Undefined representa un marcador de posición para un valor que no está definido:
BSON::Undefined.new
BSON::Decimal128
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)
BSON::Decimal128 y BigDecimal
Los métodos BigDecimal#from_bson y BigDecimal#to_bson utilizan internamente los métodos equivalentes BSON::Decimal128. Esto lleva a algunas limitaciones en los valores de BigDecimal que se pueden serializar a BSON y en aquellos que se pueden deserializar a partir de valores de BSON decimal128 existentes.
Serializar instancias de BigDecimal como instancias de BSON::Decimal128 permite una mayor flexibilidad al realizar consultas y agregaciones en MongoDB. La siguiente lista describe las limitaciones en BigDecimal:
Decimal128tiene un rango y precisión limitados, mientras queBigDecimalno tiene restricciones en cuanto a rango y precisión.Decimal128tiene un valor máximo de aproximadamente10^6145y un valor mínimo de aproximadamente-10^6145, y tiene un máximo de 34 bits de precisión.Decimal128puede aceptar valores firmados deNaN, mientras queBigDecimalno. Todos los valoresNaNfirmados que se deserialicen en instanciasBigDecimalserán sin signo.Decimal128mantiene los ceros finales al serializar a BSON y deserializar desde BSON.BigDecimal, sin embargo, no mantiene ceros finales y por lo tanto usarBigDecimalpuede resultar en 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.
Serialización JSON
Algunos BSON types tienen representaciones especiales en JSON. La siguiente tabla describe el comportamiento de serialización para los tipos especificados cuando llamas a to_json sobre ellos.
Objeto BSON de Ruby | Representación JSON |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Instancias de tiempo
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 hacia abajo. Si el tiempo precede a la Unix epoch (enero 1, 1970 00:00:00 UTC), el valor absoluto del tiempo 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 todos los cálculos de tiempo se realicen utilizando matemáticas de enteros, ya que la inexactitud de los cálculos de punto flotante podría 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.
Instancias DateTime
BSON admite el almacenamiento de valores de tiempo como el número de segundos desde la Unix epoch. Las instancias Ruby DateTime pueden serializarse a BSON, pero cuando el BSON se deserializa, estos momentos se retornarán como instancias de 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.
Instancias de fecha
BSON admite el almacenamiento de valores de tiempo como el número de segundos desde la Unix epoch. Las instancias Ruby Date pueden serializarse a BSON, pero cuando el BSON se deserializa, estos momentos se retornarán como instancias de Time.
Cuando las instancias de Date se serializan, el valor de tiempo empleado es la medianoche del Date en UTC.
Expresiones regulares
Tanto MongoDB como Ruby ofrecen soporte para trabajar con expresiones regulares, aunque utilizan motores de expresiones regulares diferentes. A continuación se detallan las diferencias entre las expresiones regulares de Ruby y las expresiones regulares de MongoDB.
Expresiones regulares de MongoDB
MongoDB utiliza expresiones regulares compatibles con Perl implementadas usando la librería PCRE. Expresiones regulares de Ruby que se implementan mediante el motor de expresiones regulares Onigmo, que es 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 forma sencilla de convertir programáticamente una expresión regular de PCRE en la expresión regular equivalente de Ruby, ya que actualmente no hay un enlace de Ruby para PCRE.
Opciones, banderas y modificadores
Tanto las expresiones regulares de Ruby como las de PCRE admiten modificadores. Estos también se llaman "opciones" en contextos de Ruby y "banderas" en contextos de 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 cambio, el modificadormde Ruby cumple la misma función que el modificadorsde PCRE, que es hacer que el punto (.) coincida con cualquier carácter, incluidas las nuevas líneas. La documentación de Ruby se refiere al modificadormcomo habilitador del modo multilínea.Ruby siempre opera en el equivalente del modo multinea de PCRE, activado por el modificador
men expresiones regulares PCRE. En Ruby, el ancla^siempre se refiere al comienzo de línea y el ancla$siempre se refiere al final de línea.
Cuando escriba expresiones regulares destinadas a utilizarse tanto en entornos Ruby como en entornos PCRE, incluidos el Servidor MongoDB y la mayoría de los demás controladores de MongoDB, evite utilizar los anclajes ^ y $. Las siguientes secciones proporcionan soluciones alternativas y recomendaciones para elaborar expresiones regulares portátiles que puedan utilizarse en múltiples contextos.
^ Ancla
En las expresiones regulares de Ruby, el ancla ^ siempre se refiere al principio de la línea. En las expresiones regulares de PCRE, el anclaje ^ se refiere al principio de la entrada por defecto, y la bandera 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:
Usa el ancla
\Apara referirse al inicio de la entrada.Utiliza el anclaje
^para hacer referencia al inicio de la línea si estableces el indicadormen las expresiones regulares de PCRE. Alternativamente, utiliza uno de los siguientes constructos que funcionan independientemente de los modificadores:(?:\A|(?<=\n)): gestionaLFyCR+LFfinales de línea(?:\A|(?<=[\r\n]))Gestiona los finales de líneaCR,LFyCR+LF
$ Ancla
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 las de PCRE admiten el ancla \z para referirse al final de la entrada, independientemente de los modificadores.
Las siguientes sugerencias le permiten escribir expresiones regulares portátiles:
Utilice el
\zancla para referirse al final de la entrada.Utiliza el anclaje
$para hacer referencia al inicio de la línea si estableces el indicadormen las expresiones regulares de PCRE. Alternativamente, utiliza uno de los siguientes constructos que funcionan independientemente de los modificadores:(?:\z|(?=\n)): gestionaLFyCR+LFfinales de línea(?:\z|(?=[\n\n]))Gestiona los finales de líneaCR,LFyCR+LF
BSON::Regexp::Sin formato
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.
Se pueden crear instancias BSON::Regexp::Raw utilizando el texto de expresión regular como string y modificadores opcionales PCRE:
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 manera 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">
Conversión de Expresiones Regulares
El siguiente código convierte una expresión regular de Ruby en una instancia de 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 de modificadores 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ó en el modificador Ruby m en el primer ejemplo del código anterior, y los dos últimos ejemplos se convirtieron en la misma expresión regular a pesar de que las expresiones regulares BSON originales tenían significados diferentes.
Cuando una expresión regular BSON utiliza los anclajes no portátiles ^ 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 de BSON, por ejemplo, como parte de una query, la expresión regular de BSON siempre tiene el modificador m configurado, reflejando el comportamiento de los anclajes ^ y $ en las expresiones regulares de Ruby.
Leer y escribir expresiones regulares
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"
Tanto las clases Regexp como BSON::Regexp::Raw implementan el método de clase from_bson que deserializa una expresión regular desde 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 usando 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/
Orden de clave
Los documentos BSON preservan el orden de las claves porque los documentos se almacenan como listas de pares clave-valor. Los hashes en Ruby también preservan el orden de las claves, por lo que el orden de las claves especificado en tu aplicación se mantiene cuando serializas un hash a un documento BSON, y cuando deserializas un documento BSON en un hash.
Claves duplicadas
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 hash no pueden tener claves duplicadas. Al serializar hashes de Ruby en documentos BSON, no se generan claves duplicadas.
Debido a que las claves en los documentos BSON siempre se almacenan como strings, especificar la misma clave como string y como símbolo en Ruby solo conserva 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 para una clave duplicada sobrescribe los valores anteriores para la misma clave.