Menu Docs
Página inicial do Docs
/ / /
Driver Ruby MongoDB
/

Tutorial do BSON

Nesta página

  • Instalação
  • Usar com ActiveSupport
  • BSON serialização
  • Buffers de bytes
  • Escrevendo
  • Leitura
  • Classes suportadas
  • BSON::Binary
  • BSON::Code
  • BSON::CodeWithScope
  • BSON::DBRef
  • BSON::Document
  • BSON::MaxKey
  • BSON::MinKey
  • BSON::ObjectId
  • BSON::Timestamp
  • BSON::Undefined
  • BSON::Decimal128
  • Symbol
  • serialização JSON
  • Instâncias de tempo
  • Instâncias de DateTime
  • Instâncias de datas
  • Expressões regulares
  • Expressões regulares Ruby versus MongoDB
  • BSON::Regexp::Raw classe
  • Conversão de expressões regulares
  • Leitura e escrita
  • Ordem das chaves
  • Chaves duplicadas

Este tutorial discute o uso da biblioteca Ruby BSON.

A biblioteca BSON pode ser instalada a partir do Rubygems manualmente ou com empacotador.

Para instalar a joia manualmente:

gem install bson

Para instalar o gem com o empacotador, inclua o seguinte em seu Gemfile:

gem 'bson'

A biblioteca BSON é compatível com MRI >= 2.5 e JRuby >= 9.2.

A serialização para classes definidas pelo ActiveSupport, como TimeWithZone, não é carregada por padrão para evitar uma dependência rígida do BSON no ActiveSupport. Ao usar o BSON em um aplicativo que também usa o ActiveSupport, o código relacionado ao ActiveSupport deve ser explicitamente exigido:

require 'bson'
require 'bson/active_support'

A obtenção da representação BSON bruta de um objeto Ruby é feita chamando to_bson no objeto Ruby, que retornará um BSON::ByteBuffer. Por exemplo:

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

A geração de um objeto a partir do BSON é feita chamando from_bson na classe que você deseja instanciar e passando uma instância BSON::ByteBuffer .

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

A biblioteca BSON 4.0 introduz o uso de buffers de bytes nativos no MRI e JRuby em vez de usar o StringIO , para melhorar o desempenho.

Para criar um ByteBuffer para escrever (ou seja, serializando para BSON), instanciam BSON::ByteBuffer sem argumentos:

buffer = BSON::ByteBuffer.new

Para escrever bytes brutos no buffer de bytes sem transformações, use os métodos put_byte e put_bytes . Eles usam uma cadeia de bytes como argumento e copiam essa cadeia de caracteres no buffer. put_byte força que o argumento seja uma string de comprimento 1; put_bytes aceita strings de qualquer comprimento. As strings podem conter bytes nulos.

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

Observação

put_byte e put_bytes não gravam um byte do tipo BSON antes de gravar o argumento no buffer de bytes.

Métodos de escrita subsequentes escrevem objetos de tipos específicos na especificação BSON. Observe que 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 fornecido a put_int32, ele será forçado em um número inteiro e o número inteiro resultante será gravado no buffer de bytes .

Para escrever uma cadeia UTF-8 (BSON tipo 0x02) no buffer de bytes, use put_string:

buffer.put_string("hello, world")

Observe que as strings BSON são sempre codificadas em UTF-8. Portanto, o argumento deve estar em UTF-8 ou em uma codificação convertível para UTF-8 (ou seja, não binário). Se o argumento estiver em uma codificação diferente de UTF-8, a string será primeiro convertida em UTF-8 e a versão codificada em UTF-8 será gravada no buffer. A string deve ser válida na codificação reivindicação, inclusive sendo UTF-8 válida se a codificação for UTF-8. A string pode conter bytes nulos.

A especificação BSON também define um tipo CString, que é usado, por exemplo, para chaves de documentos. Para escrever CStrings no buffer, use put_cstring:

buffer.put_cstring("hello, world")

Assim como nas strings regulares, as CStrings no BSON devem ser codificadas em UTF-8. Se o argumento não estiver em UTF-8, ele será convertido para 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 bytes nulos, uma vez que o formato de serialização CString em BSON tem encerramento nulo.

Ao contrário de put_string, put_cstring também aceita símbolos e inteiros. Em todos os casos, o argumento é definido como uma string antes de ser escrito:

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

Para escrever um número inteiro de 32 bits ou 64 bits 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 número inteiro de 32 ou 64 bits, put_int32 e put_int64 aumentem RangeError .

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)

Para obter os dados serializados como uma cadeia de bytes (por exemplo, para enviar os dados por um soquete), 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 escrita separadamente. Não há como retroceder o buffer para gravação - rewind afeta apenas a posição de leitura.

Para criar um ByteBuffer para leitura (ou seja, desserializando do BSON), instancie BSON::ByteBuffer com uma cadeia de bytes como argumento:

buffer = BSON::ByteBuffer.new(string) # a read mode buffer.

A leitura do buffer é feita por meio da seguinte API:

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 escrita separadamente. rewind afeta apenas a posição de leitura.

As principais classes Ruby que têm representações na especificação BSON e terão um método to_bson definido para elas são: Object, Array, FalseClass, Float, Hash, Integer, BigDecimal, NilClass, Regexp, String, Symbol (descontinuado), Time, TrueClass.

Além dos principais objetos Ruby, o BSON também fornece alguns tipos especiais específicos para a especificação:

Utilize objetos BSON::Binary para armazenar dados binários arbitrários. Os objetos Binary podem ser construídos a partir de strings binárias da seguinte forma:

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

Por padrão, objetos Binary são criados com BSON subtipo binário 0 (:generic). O subtipo pode ser explicitamente especificado 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...>

Os subtipos válidos são :generic, :function, :old, :uuid_old, :uuid, :md5 e :user.

Os dados e o subtipo podem ser recuperados de instâncias do Binary utilizando atributos do data e type , como segue:

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

Observação

BSON::Binary os objetos sempre armazenam os dados na codificação BINARY , independentemente da codificação em que a string passada para o construtor estava:

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

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 stringificar um UUID BSON::Binary para 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"

A representação padrão pode ser especificada explicitamente ao invocar os métodos from_uuid e to_uuid :

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

Observe que a representação :standard só pode ser usada com um binário do subtipo :uuid (não :uuid_old).

Os dados armazenados em objetos BSON::Binary do subtipo 3 (:uuid_old) podem ser mantidos em uma de três ordens de bytes diferentes, dependendo de qual driver criou os dados. As ordens de bytes são legado CSharp, legado Java e legado Python. A ordem de bytes legado do Python é a mesma que a ordem de bytes padrão RFC 4122; As ordens de bytes legados do C# e do legado Java têm alguns dos bytes trocados.

O objeto Binary contendo 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 usam o formato, ou representação, como argumento. Um aplicativo pode copiar objetos binários UUID legados sem saber em qual ordem de bytes eles armazenam seus dados.

Os métodos a seguir para trabalhar com UUIDs legados são fornecidos para interoperabilidade com sistemas existentes que armazenam dados em formatos UUID legados. É recomendável que novos aplicativos usem somente o formato :uuid (subtipo 4), que é compatível com a RFC 4122.

Para stringificar um UUID legado BSON::Binary, utilize o método to_uuid especificando a representação desejada. As representações aceitas são :csharp_legacy, :java_legacy e :python_legacy. Observe que um UUID legado BSON::Binary não pode ser stringified 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 especificando 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...>

Estes métodos podem ser utilizados 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"

Representa uma string de código JavaScript.

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

Observação

O tipo CodeWithScope está obsoleto a partir do MongoDB 4.2.1. A partir do MongoDB 4.4, o suporte do CodeWithScope está sendo removido de vários comandos e operadores do servidor, como $where. Use outros BSON types ao trabalhar com o MongoDB 4.4 e versões mais recentes.

Representa uma string de código JavaScript com um hash de valores.

BSON::CodeWithScope.new("this.value = age;", age: 5)

Esta é uma subclasse de BSON::Document que fornece acessadores para a coleção, id 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 validará o hash fornecido e gerará um ArgumentError se ele não for um DBRef válido. BSON::ExtJSON.parse_obj e Hash.from_bson não gerarão um erro se receberem um DBRef inválido e, em vez disso, analisarão um Hash ou desserializarão um BSON::documento.

Observação

Todos os documentos BSON são desserializados em instâncias de BSON::DBRef se forem DBRefs válidos, caso contrário, sã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

Para compatibilidade com versões 2.17 e anteriores do driver Ruby do MongoDB, BSON::DBRef também pode ser construído usando a API de driver legada. Esta API está obsoleta e será removida em uma versão futura do bson-ruby:

BSON::DBRef.new("collection", BSON::ObjectId('61eeb760a15d5d0f9f1e401d'))
BSON::DBRef.new("collection", BSON::ObjectId('61eeb760a15d5d0f9f1e401d'), "db")

Esta é uma subclasse de Hash que armazena todas as chaves como strings, mas permite acesso a elas com 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 por acaso forem um DBRef válido), 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

Representa um valor em BSON que sempre será comparado com outro valor.

BSON::MaxKey.new

Representa um valor em BSON que sempre será comparado como inferior a outro valor.

BSON::MinKey.new

Representa um identificador exclusivo de 12 bytes para um objeto em uma determinada máquina.

BSON::ObjectId.new

Representa um horário especial com um valor inicial e incremental.

BSON::Timestamp.new(5, 30)

Representa um espaço reservado para um valor que não foi fornecido.

BSON::Undefined.new

Representa um valor de ponto flutuante baseado em decimal de 128 bits capaz de 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)

Os métodos BigDecimal from_bson e to_bson utilizam os mesmos métodos BSON::Decimal128 subjacentes. Isso leva a algumas limitações que são impostas aos valores BigDecimal que podem ser serializados para BSON e àqueles que podem ser desserializados a partir de valores decimal128 BSON existentes. Essa alteração foi feita porque a serialização de instâncias BigDecimal como instâncias BSON::Decimal128 permite mais flexibilidade em termos de query e agregação no MongoDB. As limitações impostas ao BigDecimal são as seguintes:

  • decimal128 tem alcance e precisão limitados, enquanto BigDecimal não tem restrições em termos de alcance e precisão. decimal128 tem um valor máximo de aproximadamente 10^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 de NaN assinados, enquanto BigDecimal não é. Todos os valores NaN assinados que são desserializados em instâncias BigDecimal 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, usar BigDecimal pode resultar em falta de precisão.

Observação

No BSON 5.0, decimal128 é desserializado em BigDecimal por padrão. Para ter decimal128 valores em documentos BSON desserializados em BSON::Decimal128, a opção mode: :bson pode ser definida em from_bson.

A especificação BSON define um tipo de símbolo que permite percorrer valores Ruby Symbol (ou seja, um Ruby Symbol``is encoded into a BSON symbol and a BSON symbol is decoded into a Ruby ``Symbol). No entanto, como a maioria das linguagens de programação não tem um tipo de símbolo nativo, para promover a interoperabilidade, o MongoDB depreciou o tipo de símbolo BSON e incentiva o uso de strings.

Observação

No BSON, as chaves de hash são sempre strings. Os valores que não são strings se tornarão strings quando usados como chaves de hash:

Hash.from_bson({foo: 'bar'}.to_bson)
# => {"foo"=>"bar"}
Hash.from_bson({1 => 2}.to_bson)
# => {"1"=>2}

Por padrão, a biblioteca BSON codifica valores de hash Symbol como strings e decodifica símbolos BSON em valores Ruby Symbol :

{foo: :bar}.to_bson.to_s
# => "\x12\x00\x00\x00\x02foo\x00\x04\x00\x00\x00bar\x00\x00"
# 0x02 is the string type
Hash.from_bson(BSON::ByteBuffer.new("\x12\x00\x00\x00\x02foo\x00\x04\x00\x00\x00bar\x00\x00".force_encoding('BINARY')))
# => {"foo"=>"bar"}
# 0x0E is the symbol type
Hash.from_bson(BSON::ByteBuffer.new("\x12\x00\x00\x00\x0Efoo\x00\x04\x00\x00\x00bar\x00\x00".force_encoding('BINARY')))
# => {"foo"=>:bar}

Para forçar a codificação de símbolos Ruby para símbolos BSON, envolva os símbolos Ruby em BSON::Symbol::Raw:

{foo: BSON::Symbol::Raw.new(:bar)}.to_bson.to_s
# => "\x12\x00\x00\x00\x0Efoo\x00\x04\x00\x00\x00bar\x00\x00"

Alguns tipos de BSON possuem representações especiais em JSON. Eles são os seguintes e serão serializados automaticamente no formulário ao chamar to_json neles.

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

Os tempos em Ruby podem ter precisão de nanossegundos. Os horários em BSON (e MongoDB) só podem ter precisão de milissegundos. Quando as instâncias Ruby Time são serializadas para BSON ou Extended JSON, os horários são construídos para o milissegundo mais próximo.

Observação

O tempo como sempre arredondado para baixo. Se a hora preceder a Era UNIX (1º de janeiro de 1970 00:00:00 UTC), o valor absoluto da hora aumentaria:

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

Observação

JRuby a partir da versão 9.2.11.0 arredonda os tempos pré-Unix para cima em vez de para baixo. bson-Ruby funciona em torno disso e funciona corretamente os horários ao serializar no JRuby.

Devido a esse sombreamento, é altamente recomendável que os aplicativos executem todos os cálculos de tempo usando matemática numérica inteira, pois a inexatidão dos cálculos de ponto flutuante pode produzir resultados inesperados.

O BSON suporta apenas o armazenamento do tempo como o número de segundos desde a Era UNIX. As instâncias DateTime de Ruby podem ser serializadas para BSON, mas quando o BSON é desserializado, os horários serão retornados como instâncias Time .

DateTime class in Ruby suporta calendários não-greganos. Quando instâncias DateTime não-gregorianos são serializadas, elas são primeiro convertidas para o calendário Gregoriano, e a respectiva data no calendário Gregoriano é armazenada no reconhecimento de data center.

O BSON suporta apenas o armazenamento do tempo como o número de segundos desde a Era UNIX. As instâncias Date de Ruby podem ser serializadas para BSON, mas quando o BSON é desserializado, os horários serão retornados como instâncias Time .

Quando Date instâncias são serializadas, o valor de tempo utilizado é meia-noite do dia a que o Date se refere em UTC.

Tanto o MongoDB quanto o Ruby fornecem instalações para trabalhar com expressões regulares, mas usam mecanismos de expressões regulares. As subseções a seguir detalham as diferenças entre expressões regulares Ruby e expressões regulares MongoDB e descrevem como trabalhar com ambas.

O servidor MongoDB usa expressões regulares compatíveis com Perl implementadas usando a biblioteca PCRE e expressões regulares Ruby são implementadas usando o mecanismo de expressão regular Onigmo, que é uma bifurcação do Oniguruma. As duas implementações de expressão regular geralmente fornecem funcionalidade equivalente, mas têm várias diferenças de sintaxe importantes, conforme descrito abaixo.

Infelizmente, não há uma maneira simples de converter programaticamente uma expressão regular PCRE na expressão regular Ruby equivalente, e atualmente não há vinculações Ruby para PCRE.

As expressões regulares Ruby e PCRE suportam modificadores. Eles também são chamados de "opções" na linguagem Ruby e "sinalizadores" na linguagem PCRE. O significado dos modificadores s e m difere em Ruby e PCRE:

  • Ruby não tem o modificador s , em vez disso, o modificador Ruby m executa a mesma função que o modificador PCRE s , que é fazer com que o ponto ( . ) corresponda a qualquer caractere, incluindo novas linhas. De forma desconcertante, a documentação Ruby se refere ao modificador m como "habilitando 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ão destinadas a serem usadas em ambientes Ruby e PCRE (incluindo o MongoDB Server e a maioria dos outros drivers MongoDB), a partir de agora denominadas "expressão portáteis", evite usar as âncoras ^ e $ . As seções a seguir fornecem soluções alternativas e recomendações para criar expressões regulares portáteis.

Em expressões regulares Ruby, a âncora ^ sempre se refere ao início da linha. Nas 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.

Ao escrever expressões regulares portáteis:

  • Use a âncora \A para referir-se ao início da entrada.

  • Use a âncora ^ para se referir ao início da linha (isso requer a definição do sinalizador m em expressões regulares PCRE). Como alternativa, use uma das seguintes construções que funcionam independentemente dos modificadores: - (?:\A|(?<=\n)) (lida com extremidades de linha LF e CR+LF) - (?:\A|(?<=[\r\n])) (lida com extremidades de linha CR, LF e CR+LF)

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.

Ao escrever expressões regulares portáteis:

  • Use a âncora \z para referir-se ao final da entrada.

  • Use a âncora $ para se referir ao início da linha (isso requer a definição do sinalizador m em expressões regulares PCRE). Como alternativa, use uma das seguintes construções que funcionam independentemente dos modificadores: - (?:\z|(?=\n)) (lida com extremidades de linha LF e CR+LF) - (?:\z|(?=[\n\n])) (lida com extremidades de linha CR, LF e CR+LF)

Como não há uma maneira simples de converter programaticamente uma expressão PCRE na expressão Ruby equivalente, o BSON fornece a classe BSON::Regexp::Raw para manter as expressão do MongoDB/PCRE. As instâncias dessa classe são chamadas de "expressões regulares BSON" nesta documentação.

As instâncias desta classe podem ser criadas utilizando 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:: pode 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">

Para converter uma expressão regular Ruby em uma expressão regular BSON, instancie um objeto BSON::Regexp::Raw da seguinte forma:

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

Observe que o construtor BSON::Regexp::Raw aceita as opções numéricas Ruby e as strings de modificadores 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", "")
bson_regexp.compile
# => /^hello.world/
bson_regexp = BSON::Regexp::Raw.new("^hello.world", "m")
bson_regexp.compile
# => /^hello.world/

Observe que o modificador PCRE s foi convertido no modificador Ruby m no primeiro exemplo e os dois últimos exemplos foram convertidos na 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, para enviar ao servidor como parte de uma query), a expressão regular BSON sempre tem o modificador m definido refletindo o comportamento de ^ e $ âncoras em expressões regulares Ruby.

As expressões regulares Ruby e BSON implementam o método to_bson para serialização 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 acima.

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/

Os documentos BSON preservam a ordem das chaves, pois os documentos são armazenados como listas de pares chave-valor. Os hashes em Ruby também preservam a ordem das chaves; portanto, a ordem das chaves especificada em Ruby será respeitada ao serializar um hash para um documento BSON e, ao desserializar um documento BSON em um hash, a ordem das chaves no documento corresponderá à ordem das chaves no hash.

A especificação BSON permite que documentos BSON tenham chaves duplicadas, porque os documentos são armazenados como listas de pares chave-valor. A aplicação deve abster-se de gerar esse documento, porque o comportamento do MongoDB Server é indefinido quando um documento BSON contém chaves duplicadas.

Como os hashes Ruby não podem ter chaves duplicadas, ao serializar hashes Ruby para documentos BSON nenhuma chave duplicada será gerada. (Ainda é possível criar manualmente um documento BSON que teria chaves duplicadas no Ruby, e algumas das outras bibliotecas BSON do MongoDB podem permitir a criação de documentos BSON com chaves duplicadas.)

Observe que, como as chaves nos documentos BSON são sempre armazenadas como strings, especificar a mesma chave como string e um símbolo em Ruby apenas mantém 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.

Voltar

Erros comuns