Visão geral
Neste guia, você aprenderá sobre o formato de dados BSON, como o MongoDB usa o BSON para organizar e armazenar dados e como instalar a biblioteca BSON independentemente do driver Ruby.
Formato de dados JSON
BSON, ou Binary JSON, é o formato de dados que o MongoDB usa para organizar e armazenar dados. Este formato de dados inclui todos os tipos de estrutura de dados JSON e adiciona suporte para tipos incluindo datas, inteiros de tamanhos diferentes (32-bit e 64-bit), ObjectIds e dados binários. Para obter uma lista completa dos tipos compatíveis, consulte osBSON types do na documentação do MongoDB Server .
O BSON não é legível por humanos, mas você pode usar a biblioteca Ruby BSON para convertê-lo na representação JSON legível por humanos. Você pode ler mais sobre o relacionamento entre esses formatos no guia JSON e BSON no site do MongoDB.
Instale a biblioteca BSON
Você pode instalar a biblioteca BSON (bson
) do Rubygems manualmente ou usando o pacote.
Execute o seguinte comando para instalar a joia bson
:
gem install bson
Para instalar o gem usando o empacotador, inclua a seguinte linha no Gemfile
do seu aplicativo:
gem 'bson'
A biblioteca BSON é compatível com MRI v2.5 e posterior e JRuby v9.2 e posterior.
ActiveSupport
A serialização para classes definidas no Active Support, como TimeWithZone
, não é carregada por padrão para evitar uma dependência rígida do BSON no Active Support. Ao usar o BSON em um aplicação que também usa o Active Support, você deve exigir o suporte ao código do Active Support:
require 'bson' require 'bson/active_support'
BSON serialização
Você pode recuperar a representação bruta de BSON de um objeto Ruby chamando to_bson
no objeto. O método to_bson
retorna um BSON::ByteBuffer
.
O seguinte código demonstra como chamar o método to_bson
em objetos Ruby:
"Shall I compare thee to a summer's day".to_bson 1024.to_bson
Você pode gerar um objeto Ruby a partir de BSON chamando from_bson
na classe que deseja instanciar e passando uma instância BSON::ByteBuffer
:
String.from_bson(byte_buffer) BSON::Int32.from_bson(byte_buffer)
Buffers de bytes
bson
v4.0 introduz o uso de buffers de bytes nativos em MRI e JRuby em vez de usar StringIO
para melhorar o desempenho.
Escrever em um buffer de bytes
Para criar um ByteBuffer
para escrita, instancie um BSON::ByteBuffer
sem argumentos:
buffer = BSON::ByteBuffer.new
Bytes brutos
Para escrever bytes brutos no buffer de bytes sem transformações, use os métodos put_byte
e put_bytes
. Cada método usa uma string de bytes como argumento e copia essa string para o buffer. O método put_byte
impõe que o argumento é uma string de comprimento 1
. put_bytes
aceita qualquer comprimento de strings. As strings podem conter bytes nulos.
O seguinte código demonstra como escrever bytes brutos em um buffer de bytes:
buffer.put_byte("\x00") buffer.put_bytes("\xff\xfe\x00\xfd")
Observação
put_byte
e put_bytes
não grava um byte do tipo BSON no buffer antes de gravar a cadeia de bytes. Isso significa que o buffer não fornece informações sobre o tipo de dados que a string de bytes bruta codifica.
Métodos de gravação de bytes digitados
Os métodos de gravação descritos nas seções a seguir gravam objetos de tipos específicos na especificação BSON. O tipo indicado pelo nome do método tem precedência sobre o tipo do argumento. Por exemplo, se um valor de ponto flutuante for passado para put_int32
, ele será forçado em um número inteiro, e o driver gravará o número inteiro resultante no buffer de bytes.
Strings
Para escrever uma string UTF-8 (BSON tipo 0x02) no buffer de bytes, use o método put_string
:
buffer.put_string("hello, world")
As strings JSON são sempre codificadas em UTF-8. Isso significa que o argumento para put_string
deve estar em UTF-8 ou em uma codificação convertível em UTF-8 (não binária). Se o argumento estiver em uma codificação diferente de UTF-8, a string será primeiro convertida em UTF-8 e, em seguida, a versão codificada em UTF-8 será gravada no buffer. A string deve ser válida na codificação solicitada. A string pode conter bytes nulos.
A especificação BSON também define um tipo CString, que é usado, por exemplo, para chaves de documento . Para escrever CStrings no buffer, use put_cstring
:
buffer.put_cstring("hello, world")
Assim como nas strings regulares, as CStrings em BSON devem ser codificadas em UTF-8. Se o argumento não estiver em UTF-8, ele será convertido em UTF-8 e a string resultante será gravada no buffer. Ao contrário de put_string
, a codificação UTF-8 do argumento fornecido a put_cstring
não pode ter nenhum byte nulo, pois o formato de serialização CString em BSON é terminado em nulo.
Ao contrário de put_string
, put_cstring
também aceita símbolos e números inteiros. Em todos os casos, o argumento é string antes de ser gravado no buffer:
buffer.put_cstring(:hello) buffer.put_cstring(42)
Números
Para escrever um número inteiro de 32bits ou 64bits no buffer de bytes, use os métodos put_int32
e put_int64
, respectivamente. Observe que os números inteiros Ruby podem ser arbitrariamente grandes; se o valor que está sendo gravado exceder o intervalo de um 32bits ou um número inteiro de 64bits, put_int32
e put_int64
gerarão um erro RangeError
.
O seguinte código demonstra como escrever valores inteiros em um buffer de bytes:
buffer.put_int32(12345) buffer.put_int64(123456789012345)
Observação
Se put_int32
ou put_int64
receberem argumentos de ponto flutuante, os argumentos serão primeiro convertidos em inteiros e os inteiros serão gravados no buffer de bytes.
Para escrever um valor de ponto flutuante de 64 bits no buffer de bytes, use put_double
:
buffer.put_double(3.14159)
Converter bytes em strings
Para recuperar os dados serializados como uma string de bytes, chame to_s
no buffer:
buffer = BSON::ByteBuffer.new buffer.put_string('testing') socket.write(buffer.to_s)
Observação
ByteBuffer
mantém o controle das posições de leitura e gravação separadamente. Não há como retroceder o buffer para gravação. O método rewind
afeta somente a posição de leitura.
Ler de um buffer de bytes
Para criar um ByteBuffer
para leitura ou desserialização a partir de BSON, instancie BSON::ByteBuffer
com uma string de bytes como argumento:
buffer = BSON::ByteBuffer.new(string)
Você pode ler a partir do buffer usando os seguintes métodos que correspondem a diferentes tipos de dados:
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 a leitura a partir do início de um buffer, use rewind
:
buffer.rewind
Observação
ByteBuffer
mantém o controle das posições de leitura e gravação separadamente. O método rewind
afeta somente a posição de leitura.
Classes suportadas
A lista seguinte fornece as classes Ruby que têm representações na especificação BSON e têm um método to_bson
definido:
Object
Array
FalseClass
Float
Hash
Integer
BigDecimal
NilClass
Regexp
String
Symbol
(obsoleto)Time
TrueClass
Além dos objetos Ruby principais, o BSON também fornece alguns tipos especiais específicos para a especificação. As seções a seguir descrevem outros tipos suportados no driver.
BSON::Binary
Use objetos BSON::Binary
para armazenar dados binários arbitrários. Você pode construir Binary
objetos a partir de strings binárias, como mostrado no seguinte código:
BSON::Binary.new("binary_string") # => <BSON::Binary:0x47113101192900 type=generic data=0x62696e6172795f73...>
Por padrão, os objetos Binary
são criados com subtipo binário BSON 0 (:generic
). Você pode especificar explicitamente o subtipo para indicar que os bytes codificam um tipo específico de dados:
BSON::Binary.new("binary_string", :user) # => <BSON::Binary:0x47113101225420 type=user data=0x62696e6172795f73...>
A lista a seguir fornece as especificações válidas do subtipo:
:generic
:function
:old
:uuid_old
:uuid
:md5
:ciphertext
:column
:sensitive
:vector
:user
Você pode usar os atributos data
e type
para recuperar os dados de um objeto Binary
e o subtipo, conforme mostrado no código a seguir:
binary = BSON::Binary.new("binary_string", :user) binary.data # => "binary_string" binary.type # => :user
Você pode comparar Binary
objetos usando o operador <=>
, que permite classificar objetos que têm o mesmo subtipo binário. Para comparar objetos Binary
, certifique-se de instalar a v5.0.2 ou posterior da biblioteca BSON.
Observação
Codificação BINARY
BSON::Binary
os objetos sempre armazenam os dados na codificação BINARY
, independentemente da codificação da string passada para o construtor:
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 de UUID
Para criar um UUID BSON::Binary
(subtipo binário 4) a partir de sua representação de string compatível com RFC 4122, use o 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 restringir um UUID BSON::Binary
a uma representação compatível com RFC 4122, use o 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"
Você pode especificar explicitamente a representação padrão do UUID nos métodos from_uuid
e to_uuid
:
binary = BSON::Binary.from_uuid(uuid_str, :standard) binary.to_uuid(:standard)
Você pode usar a representação :standard
somente com um valor Binary
do subtipo :uuid
, não :uuid_old
.
UUIDs legados
Os dados armazenados em BSON::Binary
objetos de subtipo 3 (:uuid_old
) podem ser persistentes em uma das três ordens de bytes diferentes, dependendo do driver que criou os dados. As ordens de bytes são legado C# , legado Java e legado Python . A ordem de bytes legado do Python é a mesma que a ordem de bytes padrão da RFC 4122. As ordens de bytes C# legado e Java legado têm alguns dos bytes em locais diferentes.
O objeto Binary
que contém um UUID legado não codifica em qual formato o UUID está armazenado. Portanto, os métodos que convertem de e para o formato UUID legado utilizam o formato, ou representação, como argumento. Um aplicação pode copiar objetos legado do UUID Binary
sem saber em qual ordem de bytes eles armazenam seus dados.
Os métodos a seguir para trabalhar com UUIDs legado são fornecidos para interoperabilidade com sistemas existentes que armazenam dados em formatos UUID legado . Em novos aplicativos, use somente o formato :uuid
(subtipo 4), que é compatível com RFC 4122.
Para stringificar um UUID legado BSON::Binary
, utilize o método to_uuid
e especifique a representação desejada. As representações aceitas são :csharp_legacy
, :java_legacy
e :python_legacy
. Um UUID BSON::Binary
legado não pode ser em string sem especificar uma representação.
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 criar um UUID legado BSON::Binary
a partir da representação de string do UUID, utilize o método from_uuid
e especifique a representação desejada:
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...>
Você pode usar esses métodos para converter de uma representação para outra:
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, você pode usar o tipo BSON::Vector
para representar vetores de valores numéricos.
Você pode criar um objeto BSON::Vector
para armazenar valores dos seguintes tipos:
int8
float32
packed_bit
Você pode utilizar os atributos opcionais dtype
e padding
para especificar o tipo de dados do vetor e o preenchimento de bits, respectivamente. BSON::Vector
em si é um contêiner para manter seus valores de array, tipo de informações e especificação de preenchimento. BSON::Vector
objetos são serializados como arrays normais no MongoDB.
O exemplo a seguir demonstra como criar um objeto BSON::Vector
:
BSON::Vector.new([ -0.0016261312, -0.028070757, -0.011342932 ], :float32)
Converter vetores em binário
Você pode converter BSON::Vector
e objetos de array em objetos BSON::Binary para que sejam serializados como instâncias de vetor binário BSON (subtipo 9). Use o método BSON::Binary.from_vector
, conforme mostrado no código a seguir:
vector = BSON::Vector.new([ -0.0016261312, -0.028070757, -0.011342932 ], :float32) BSON::Binary.from_vector(vector)
Usar o tipo BSON::Binary
melhora a eficiência do armazenamento. Para saber mais, consulte a especificação BSON.
Você pode converter um BSON::Binary
para um BSON::Vector
utilizando o método BSON::Binary.as_vector
.
Dica
Atlas Vector Search
Para ver um exemplo que aproveita o tipo BSON::Binary
para executar queries eficientes do Atlas Vector Search, consulte osExemplos de query do Atlas Search .
BSON::Code
Este tipo representa uma string de código JavaScript:
BSON::Code.new("this.value = 5;")
BSON::DBRef
Esta é uma subclasse de BSON::Document
que fornece acessadores para a coleção, identificador e banco de dados do DBRef
.
BSON::DBRef.new({"$ref" => "collection", "$id" => "id"}) BSON::DBRef.new({"$ref" => "collection", "$id" => "id", "database" => "db"})
Observação
O construtor BSON::DBRef
valida o hash fornecido e gera um ArgumentError
se não for um DBRef
válido. Os métodos BSON::ExtJSON.parse_obj
e Hash.from_bson
não geram um erro se for passado um DBRef
inválido e, em vez disso, analisam um Hash
ou desserializam um BSON::Document
.
Observação
Todos os documentos BSON são desserializados em instâncias de BSON::DBRef
se forem instâncias de DBRef
válidas, caso contrário, serão desserializados em instâncias de BSON::Document
. Isso é verdadeiro mesmo quando a invocação é feita a partir da classe 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
BSON::Document
é uma subclasse de Hash
que armazena todas as chaves como strings, mas permite acessá-las usando chaves de símbolo.
BSON::Document[:key, "value"] BSON::Document.new
Observação
Todos os documentos BSON são desserializados em instâncias de BSON::Document
ou BSON::DBRef
, se forem instâncias DBRef
válidas, mesmo quando a invocação é feita a partir da classe 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 um valor no BSON que sempre compara mais alto do que qualquer outro valor:
BSON::MaxKey.new
BSON::MinKey
BSON::MinKey
representa um valor no BSON que sempre compara menor do que qualquer outro valor:
BSON::MinKey.new
BSON::ObjectId
BSON::ObjectId
representa um identificador exclusivo de 12 bytes para um objeto:
BSON::ObjectId.new
BSON::Timestamp
BSON::Timestamp
representa um tempo com um valor de início e incremento:
BSON::Timestamp.new(5, 30)
BSON::Indefinido
BSON::Undefined
representa um espaço reservado para um valor indefinido:
BSON::Undefined.new
BSON::Decimal128
BSON::Decimal128
representa um valor de ponto flutuante baseado em decimal de 128bits que pode emular arredondamentos decimais com precisão exata:
# Instantiate with a String BSON::Decimal128.new("1.28") # Instantiate with a BigDecimal d = BigDecimal(1.28, 3) BSON::Decimal128.new(d)
BSON::Decimal128 e BigDecimal
Os métodos BigDecimal#from_bson
e BigDecimal#to_bson
utilizam os métodos BSON::Decimal128
equivalentes internamente. Isso leva a algumas limitações nos valores BigDecimal
que podem ser serializados para BSON e aqueles que podem ser desserializados a partir de valores BSON decimal128
existentes.
A serialização de instâncias BigDecimal
como instâncias BSON::Decimal128
permite mais flexibilidade ao consultar e executar agregações no MongoDB. A seguinte lista descreve as limitações no BigDecimal
:
Decimal128
tem alcance e precisão limitados, enquantoBigDecimal
não tem restrições em termos de alcance e precisão.Decimal128
tem um valor máximo de aproximadamente10^6145
e um valor mínimo de aproximadamente-10^6145
, e tem um máximo de 34 bits de precisão.Decimal128
é capaz de aceitar valores deNaN
assinados, enquantoBigDecimal
não é. Todos os valoresNaN
assinados que são desserializados em instânciasBigDecimal
não serão assinados.Decimal128
mantém os zeros finais ao serializar e desserializar do BSON.BigDecimal
, no entanto, não mantém zeros à direita e, portanto, usarBigDecimal
pode resultar em falta de precisão.
Observação
Na biblioteca BSON v5.0, Decimal128
é desserializado em BigDecimal
por padrão. Para ter Decimal128
valores em documentos BSON desserializados em BSON::Decimal128
, você pode definir a opção mode: :bson
ao chamar from_bson
.
serialização JSON
Alguns tipos de BSON têm representações especiais em JSON. A tabela a seguir descreve o comportamento de serialização para os tipos especificados quando você chama to_json
neles.
Objeto BSON de rubi | Representação JSON |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Instâncias de tempo
Os tempos em Ruby têm precisão de nanossegundos. Os tempos no BSON têm precisão de milissegundos. Quando você serializa instâncias Ruby Time
para BSON ou Extended JSON, os tempos são arredondados para o milissegundo mais próximo.
Observação
Os valores de tempo são arredondados para baixo. Se o tempo preceder a época do Unix (janeiro de 1, 1970 00:00:00 UTC), o valor absoluto do tempo aumenta:
time = Time.utc(1960, 1, 1, 0, 0, 0, 999_999) time.to_f # => -315619199.000001 time.floor(3).to_f # => -315619199.001
Devido a esse comportamento de arredondamento, recomendamos que você execute todos os cálculos de tempo usando a matemática inteira, pois a inexatidão dos cálculos de ponto flutuante pode produzir resultados inesperados.
Observação
JRuby 9.2.11.0 arredonda os tempos pré-Unix para cima em vez de para baixo. Para saber mais sobre esse comportamento, consulte o problema relacionado do Github. A biblioteca BSON corrige esse comportamento e limita os horários ao serializar no JRuby.
Instâncias de DateTime
O BSON suporta o armazenamento de valores de tempo como o número de segundos desde a Unix epoch. As instâncias DateTime
ruby podem ser serializadas para BSON, mas quando o BSON for desserializado, os horários serão retornados como instâncias Time
.
A classe DateTime
em Ruby suporta calendários não gregorianos. Quando as instâncias não gregorianos DateTime
são serializadas, elas são primeiro convertidas para o calendário gregoriano, e a respectiva data no calendário gregoriano é armazenada no banco de dados.
Instâncias de datas
O BSON suporta o armazenamento de valores de tempo como o número de segundos desde a Unix epoch. As instâncias Date
ruby podem ser serializadas para BSON, mas quando o BSON for desserializado, os horários serão retornados como instâncias Time
.
Quando as instâncias Date
são serializadas, o valor de tempo usado é meia-noite no Date
em UTC.
Expressões regulares
Tanto o MongoDB quanto o Ruby oferecem suporte para trabalhar com expressões regulares, mas usam mecanismos de expressão regular. As subseções a seguir detalham as diferenças entre expressões regulares Ruby e expressões regulares MongoDB .
Expressões regulares do MongoDB
O MongoDB usa expressões regulares compatíveis com Perl implementadas usando a biblioteca PCRE. As expressões regulares Ruby são implementadas usando o mecanismo de expressão regular Onigmo, que é uma bifurcação da biblioteca Oniguruma.
As duas implementações de expressão regular geralmente fornecem funcionalidade equivalente, mas têm várias diferenças de sintaxe importantes, descritas nas seções a seguir.
Não existe uma maneira simples de converter programaticamente uma expressão regular PCRE na expressão regular Ruby equivalente, pois atualmente não há vinculações Ruby para PCRE.
Opções, sinalizadores e modificadores
As expressões regulares Ruby e PCRE suportam modificadores. Eles também são chamados de "opções" em contextos Ruby e "sinalizadores" em contextos PCRE. O significado dos modificadores s
e m
difere em Ruby e PCRE das seguintes maneiras:
Ruby não tem o modificador
s
. Em vez disso, o modificador Rubym
executa a mesma função que o modificador PCREs
, que é fazer com que o ponto (.
) corresponda a qualquer caractere, incluindo novas linhas. A documentação Ruby refere-se ao modificadorm
como ativando o modo de várias linhas.Ruby sempre opera no equivalente do modo multilinha do PCRE, habilitado pelo modificador
m
em expressões regulares PCRE. Em Ruby, a âncora^
sempre se refere ao início da linha e a âncora$
sempre se refere ao final da linha.
Ao escrever expressões regulares destinadas ao uso em ambientes Ruby e PCRE, incluindo o MongoDB Server e a maioria dos outros drivers do MongoDB , evite usar as âncoras ^
e $
. As seções a seguir fornecem soluções alternativas e recomendações para a criação de expressões regulares móveis que podem ser usadas em vários contextos.
^ Anchor
Em expressões regulares Ruby, a âncora ^
sempre se refere ao início da linha. Em expressões regulares PCRE, a âncora ^
refere-se ao início da entrada por padrão, e o sinalizador m
altera seu significado para o início da linha.
As expressões regulares Ruby e PCRE suportam a âncora \A
para se referir ao início da entrada, independentemente dos modificadores. As seguintes sugestões permitem a você escrever expressões regulares portabilidade:
Use a âncora
\A
para referir-se ao início da entrada.Use a âncora
^
para se referir ao início da linha se você definir o sinalizadorm
em expressões regulares PCRE. Como alternativa, use uma das seguintes construções que funcionam independentemente dos modificadores:(?:\A|(?<=\n))
: lida comLF
eCR+LF
extremidades de linha(?:\A|(?<=[\r\n]))
: lida comCR
,LF
eCR+LF
extremidades de linha
$ Anchor
Em expressões regulares Ruby, a âncora $
sempre se refere ao final da linha. Nas expressões regulares PCRE, a âncora $
refere-se ao final da entrada por padrão e o sinalizador m
altera seu significado para o final da linha.
As expressões regulares Ruby e PCRE suportam a âncora \z
para se referir ao final da entrada, independentemente dos modificadores.
As seguintes sugestões permitem a você escrever expressões regulares portabilidade:
Use a âncora
\z
para referir-se ao final da entrada.Use a âncora
$
para se referir ao início da linha se você definir o sinalizadorm
em expressões regulares PCRE. Como alternativa, use uma das seguintes construções que funcionam independentemente dos modificadores:(?:\z|(?=\n))
: lida comLF
eCR+LF
extremidades de linha(?:\z|(?=[\n\n]))
: lida comCR
,LF
eCR+LF
extremidades de linha
BSON::Regexp::Raw
Como não há uma maneira simples de converter programaticamente uma expressão regular PCRE na expressão regular Ruby equivalente, a biblioteca BSON fornece a classe BSON::Regexp::Raw
para armazenar expressões regulares PCRE.
Você pode criar instâncias BSON::Regexp::Raw
usando o texto de expressão regular como uma string e modificadores PCRE opcionais:
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">
O módulo BSON::Regexp
está incluído na classe Ruby Regexp
, de modo que o prefixo BSON::
possa ser omitido:
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">
Conversão de expressões regulares
O seguinte código converte uma expressão regular Ruby em uma instância do 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>
O construtor BSON::Regexp::Raw
aceita as opções numéricas Ruby e as strings modificadoras PCRE.
Para converter uma expressão regular BSON em uma expressão regular Ruby, chame o método compile
na expressão 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/
O modificador s
PCRE foi convertido para o modificador m
Ruby no primeiro exemplo do código anterior, e os dois últimos exemplos foram convertidos para a mesma expressão regular, embora as expressões regulares BSON originais tenham significados diferentes.
Quando uma expressão regular BSON utiliza as âncoras não portáteis ^
e $
, sua conversão para uma expressão regular Ruby pode alterar seu significado:
BSON::Regexp::Raw.new("^hello.world", "").compile =~ "42\nhello world" # => 3
Quando uma expressão regular Ruby é convertida em uma expressão regular BSON , por exemplo , como parte de uma query, a expressão regular BSON sempre tem o conjunto de modificadores m
, refletindo o comportamento de ^
e $
âncoras em expressões regulares Ruby .
Ler e escrever Regex
As expressões regulares Ruby e BSON implementam o método to_bson
para serializar para 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"
As classes Regexp
e BSON::Regexp::Raw
implementam o método de classe from_bson
que desserializa uma expressão regular de um buffer de bytes BSON. Os métodos de ambas as classes retornam uma instância BSON::Regexp::Raw
que deve ser convertida em uma expressão regular Ruby usando o método compile
, conforme descrito no código anterior.
O seguinte código demonstra como utilizar o método from_bson
para desserializar uma expressão 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/
Ordem das chaves
Documentos JSON preservam a ordem das chaves, pois os documentos são armazenados como listas de pares de chave-valor. Os hashes em Ruby também preservam a ordem das chaves, portanto, a ordem das chaves especificadas em seu aplicação é preservada quando você serializa um hash para um documento BSON e quando desserializa um documento BSON em um hash.
Chaves duplicadas
A especificação BSON permite que documentos BSON tenham chaves duplicadas, porque os documentos são armazenados como listas de pares de chave-valor. Evite criar documentos que contenham chaves duplicadas, pois o comportamento do MongoDB Server é indefinido quando um documento BSON contém chaves duplicadas.
Em Ruby, os hashes não podem ter chaves duplicadas. Quando você serializa hashes Ruby para documentos BSON, nenhuma chave duplicada é gerada.
Como as chaves em documentos BSON são sempre armazenadas como strings, especificar a mesma chave como string e um símbolo em Ruby mantém apenas a especificação mais recente:
BSON::Document.new(test: 1, 'test' => 2) # => {"test"=>2}
Ao carregar um documento BSON com chaves duplicadas, o último valor para uma chave duplicada substitui os valores anteriores para a mesma chave.