Overview
在本指南中,您可以学习;了解BSON数据格式、 MongoDB如何使用BSON组织和存储数据,以及如何独立于Ruby驾驶员安装BSON库。
BSON 数据格式
BSON (即 Binary JSON)是MongoDB用于组织和存储数据的数据格式。 此数据格式包括所有JSON数据结构类型,并增加了对日期、不同大小的整数( 32位和64位)、ObjectId 和二进制数据等类型的支持。 有关支持类型的完整列表,请参阅BSON types MongoDB Server文档中的 。
BSON不适合人类阅读,但您可以使用Ruby BSON库将其转换为人类可读的JSON表示形式。您可以在MongoDB网站上的JSON和BSON指南中详细了解这些格式之间的关系。
安装 BSON 库
您可以手动或使用捆绑程序从Rubygems安装BSON库 (bson)。
运行以下命令以安装 bson gem:
gem install bson
要使用捆绑器安装 gem,请在应用程序的 Gemfile 中包含以下行:
gem 'bson'
BSON库与 MRI v2.5 及更高版本以及 JRuby v9.2 及更高版本兼容。
ActiveSupport
默认下,不会加载 Active Support 中定义的类的序列化(例如 TimeWithZone),以避免BSON对 Active Support 的硬依赖。在也使用 Active Support 的应用程序中使用BSON时,您必须要求 Active Support 代码支持:
require 'bson' require 'bson/active_support'
BSON 序列化
您可以通过在对象上调用 to_bson检索Ruby对象的原始BSON表示形式。to_bson 方法返回 BSON::ByteBuffer。
以下代码演示了如何在Ruby对象上调用 to_bson 方法:
"Shall I compare thee to a summer's day".to_bson 1024.to_bson
您可以从BSON生成Ruby对象,方法是对要实例化的类调用 from_bson 并向其传递 BSON::ByteBuffer实例:
String.from_bson(byte_buffer) BSON::Int32.from_bson(byte_buffer)
字节缓冲区
bson v4.0 在 MRI 和 JRuby 中引入使用原生字节缓冲区,而不是使用 StringIO,从而提高性能。
写入字节缓冲区
要创建用于写入的 ByteBuffer,请实例化一个不带参数的 BSON::ByteBuffer:
buffer = BSON::ByteBuffer.new
原始字节
要将原始字节写入字节缓冲区而不进行转换,请使用 put_byte 和 put_bytes 方法。每个方法都将字节字符串作为参数,并将该字符串复制到缓冲区中。 put_byte 方法强制参数为长度为 1 的字符串。 put_bytes 接受任意长度的字符串。字符串可以包含 null 字节。
以下代码演示了如何写入字节缓冲区:
buffer.put_byte("\x00") buffer.put_bytes("\xff\xfe\x00\xfd")
注意
put_byte 并且 put_bytes 在写入字节字符串之前不会写入BSON类型字节写入缓冲区。 这意味着缓冲区不提供有关原始字节字符串编码的数据类型的信息。
类型化字节写入方法
以下部分中描述的写入方法写入BSON规范中特定类型的对象。方法名称表示的类型优先于参数的类型。示例,如果将浮点值传递给 put_int32,则会将其强制转换为整数,驾驶员会将生成的整数写入字节缓冲区。
字符串
写入UTF-8 字符串(BSON类型 0x02)写入字节缓冲区,请使用 put_string 方法:
buffer.put_string("hello, world")
BSON字符串始终以 UTF-8 编码。这意味着 put_string 的参数必须采用 UTF-8 格式或可转换为 UTF-8 的编码格式(非二进制)。如果参数采用 UTF-8 以外的编码,则首先将该字符串转换为 UTF-8,然后将 UTF-8 编码版本写入缓冲区。 该字符串在其声明的编码中必须有效。 该字符串可以包含 null 字节。
BSON规范还定义了 CString 类型,示例用于文档键。要将 CString写入缓冲区,请使用 put_cstring:
buffer.put_cstring("hello, world")
与常规字符串一样, BSON中的 CString 必须采用 UTF-8 编码。如果参数不是 UTF-8 格式,则会转换为 UTF-8 格式,并将生成的字符串写入缓冲区。 与 put_string 不同,传递给 put_cstring 的参数的 UTF-8 编码不能包含任何 null 字节,因为BSON中的 CString 序列化格式是以 null 值终止的。
与 put_string 不同,put_cstring 也接受符号和整数。在所有情况下,参数在写入缓冲区之前都会进行字符串化:
buffer.put_cstring(:hello) buffer.put_cstring(42)
数字
要将 32 位或 64 位整数写入字节缓冲区,请分别使用 put_int32 和 put_int64 方法。请注意, Ruby整数可以是任意大;如果写入的值超出 32 位或 64 位整数的范围,则 put_int32 和 put_int64 会引发 RangeError 错误。
以下代码演示了如何写入字节缓冲区:
buffer.put_int32(12345) buffer.put_int64(123456789012345)
注意
如果put_int32或put_int64提供了浮点参数,则这些参数首先会被强制转换为整数,然后将整数写入字节缓冲区。
要将 64 位浮点值写入字节缓冲区,请使用put_double :
buffer.put_double(3.14159)
将字节转换为字符串
要检索字节字符串形式的序列化数据,请在缓冲区上调用 to_s:
buffer = BSON::ByteBuffer.new buffer.put_string('testing') socket.write(buffer.to_s)
注意
ByteBuffer 分别追踪读取和写入位置。无法回滚缓冲区以进行写入。rewind 方法仅影响读取位置。
从字节缓冲区读取
要创建 ByteBuffer 以便从BSON读取或反序列化,请使用字节字符串作为参数来实例化 BSON::ByteBuffer:
buffer = BSON::ByteBuffer.new(string)
您可以使用以下对应不同数据类型的方法从缓冲区读取数据:
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
要从缓冲区的开头重新开始读取,请使用rewind :
buffer.rewind
注意
ByteBuffer 分别追踪读取和写入位置。rewind 方法仅影响读取位置。
支持的类
以下列表提供了在BSON规范中具有表示形式并定义了 to_bson 方法的Ruby类:
ObjectArrayFalseClassFloatHashIntegerBigDecimalNilClassRegexpStringSymbol(已弃用)TimeTrueClass
除了核心Ruby对象之外, BSON还提供了一些特定于规范的特殊类型。以下部分介绍了驾驶员支持的其他类型。
BSON::Binary
使用 BSON::Binary 对象存储任意二进制数据。您可以从二进制字符串构造 Binary 对象,如以下代码所示:
BSON::Binary.new("binary_string") # => <BSON::Binary:0x47113101192900 type=generic data=0x62696e6172795f73...>
默认下,使用BSON二进制子类型 0 (:generic) 创建 Binary 对象。您可以显式指定子类型以指示字节对特定数据类型进行编码:
BSON::Binary.new("binary_string", :user) # => <BSON::Binary:0x47113101225420 type=user data=0x62696e6172795f73...>
以下列表提供了有效的子类型规范:
:generic:function:old:uuid_old:uuid:md5:ciphertext:column:sensitive:vector:user
您可以使用 data 和 type 属性来检索Binary 对象的数据和子类型,如以下代码所示:
binary = BSON::Binary.new("binary_string", :user) binary.data # => "binary_string" binary.type # => :user
您可以使用 <=>操作符比较 Binary 对象,这允许您对具有相同二进制子类型的对象进行排序。要比较 Binary 对象,请确保安装BSON库 v5.0.2 或更高版本。
注意
BINARY 编码
BSON::Binary 对象始终以 BINARY 编码存储数据,而无论传递给构造函数的字符串的编码如何:
str = "binary_string" str.encoding # => #<Encoding:US-ASCII> binary = BSON::Binary.new(str) binary.data # => "binary_string" binary.data.encoding # => #<Encoding:ASCII-8BIT>
UUID 方法
要从其符合 RFC 4122 的字符串表示形式创建 UUID BSON::Binary(二进制子类型 4),请使用 from_uuid 方法:
uuid_str = "00112233-4455-6677-8899-aabbccddeeff" BSON::Binary.from_uuid(uuid_str) # => <BSON::Binary:0x46986653612880 type=uuid data=0x0011223344556677...>
要将 UUID BSON::Binary 字符串化为符合 RFC 4122 的表示形式,请使用 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"
您可以在 from_uuid 和 to_uuid 方法中显式指定标准 UUID 表示形式:
binary = BSON::Binary.from_uuid(uuid_str, :standard) binary.to_uuid(:standard)
您只能将 :standard 表示形式与子类型 :uuid 的 Binary 值一起使用,而不能与 :uuid_old 一起使用。
旧版 UUID
存储在子类型 3 (:uuid_old) 的 BSON::Binary 对象中的数据可以按三种不同字节顺序之一持久保存,具体取决于创建数据的驾驶员。字节顺序为C#传统、 Java传统和Python传统。 Python传统字节顺序与标准 RFC 4122 字节顺序相同。C#传统字节顺序和Java传统字节顺序的某些字节位于不同位置。
包含旧版 UUID 的 Binary 对象不会对该UUID的存储格式进行编码。因此,与传统 UUID 格式相互转换的方法将所需的格式或表示形式作为参数。应用程序可能会复制传统 UUID Binary 对象,而不知道它们以哪种字节顺序存储数据。
提供了以下处理传统 UUID 的方法,以便与以传统 UUID 格式存储数据的现有部署实现互操作性。在新应用程序中,仅使用符合 RFC 4122 的 :uuid(子类型 4)格式。
要将传统 UUID BSON::Binary 字符串化,请使用 to_uuid 方法并指定所需的表示形式。可接受的表示形式为 :csharp_legacy、:java_legacy 和 :python_legacy。如果不指定表示形式,则无法对旧版 UUID BSON::Binary 进行字符串化。
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"
要从 UUID 的字符串表示形式创建传统 UUID BSON::Binary,请使用 from_uuid 方法并指定所需的表示形式:
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...>
您可以使用这些方法从一种表示形式转换为另一种表示形式:
BSON::Binary.from_uuid('77665544-3322-1100-ffeeddccbbaa9988',:java_legacy).to_uuid(:csharp_legacy) # => "33221100-5544-7766-8899aabbccddeeff"
BSON::Vector
从 bson v5.1 开始,您可以使用 BSON::Vector 类型来表示数值向量。
您可以创建 BSON::Vector对象来存储以下类型的值:
int8float32packed_bit
您可以使用可选的 dtype 和 padding 属性分别指定向量的数据类型和位填充。BSON::Vector 本身是一个容器,用于保存大量值、类型信息和填充规范。BSON::Vector 对象在MongoDB中被序列化为普通数组。
以下示例演示了如何创建 BSON::Vector对象:
BSON::Vector.new([ -0.0016261312, -0.028070757, -0.011342932 ], :float32)
将向量转换为二进制
您可以将 BSON::Vector 和大量对象转换为BSON::Binary 对象,以便将它们序列化为BSON二进制向量(子类型 9)实例。使用 BSON::Binary.from_vector 方法,如以下代码所示:
vector = BSON::Vector.new([ -0.0016261312, -0.028070757, -0.011342932 ], :float32) BSON::Binary.from_vector(vector)
使用 BSON::Binary 类型可提高存储效率。要学习;了解更多信息,请参阅BSON规范。
您可以使用 BSON::Binary.as_vector 方法将 BSON::Binary 转换为 BSON::Vector。
BSON::Code
该类型表示JavaScript代码的字符串:
BSON::Code.new("this.value = 5;")
BSON::DBRef
这是 BSON::Document 的子类,为 DBRef 的集合、标识符和数据库提供访问器。
BSON::DBRef.new({"$ref" => "collection", "$id" => "id"}) BSON::DBRef.new({"$ref" => "collection", "$id" => "id", "database" => "db"})
注意
BSON::DBRef 构造函数会验证给定的哈希,如果它不是有效的 DBRef,则会引发 ArgumentError。如果向 BSON::ExtJSON.parse_obj 和 Hash.from_bson 方法传递了无效的 DBRef,则不会引发错误,而是会解析 Hash 或反序列化 BSON::Document。
注意
如果所有BSON文档是有效的 DBRef 实例,则它们都将反序列化为 BSON::DBRef 的实例,否则它们将反序列化为 BSON::Document 的实例。即使从 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 是 Hash 的子类,它将所有键存储为字符串,但允许使用符号键来访问权限这些键。
BSON::Document[:key, "value"] BSON::Document.new
注意
所有BSON文档都会反序列化为 BSON::Document 或 BSON::DBRef 的实例(如果它们是有效的 DBRef 实例),即使从 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 表示BSON中的一个值,该值始终高于任何其他值:
BSON::MaxKey.new
BSON::MinKey
BSON::MinKey 表示BSON中的值,该值始终低于任何其他值:
BSON::MinKey.new
BSON::ObjectId
BSON::ObjectId 表示对象的 12 字节唯一标识符:
BSON::ObjectId.new
BSON::Timestamp
BSON::Timestamp 表示具有起始值和增量值的时间:
BSON::Timestamp.new(5, 30)
BSON::Undefined
BSON::Undefined 表示未定义值的占位符:
BSON::Undefined.new
BSON::Decimal128
BSON::Decimal128 表示 128 位基于十进制的浮点值,可以以精确的精度模拟十进制舍入:
# Instantiate with a String BSON::Decimal128.new("1.28") # Instantiate with a BigDecimal d = BigDecimal(1.28, 3) BSON::Decimal128.new(d)
BSON::Decimal128 和 BigDecimal
BigDecimal#from_bson 和 BigDecimal#to_bson 方法在内部使用等效的 BSON::Decimal128 方法。这会导致对可序列化为BSON 的BigDecimal 值以及可从现有 decimal128 BSON值反序列化的值存在一些限制。
将 BigDecimal 实例序列化为 BSON::Decimal128 实例可在MongoDB中查询和执行聚合时提供更大的灵活性。以下列表描述了对 BigDecimal 的限制:
Decimal128的范围和精度有限,而BigDecimal在范围和精度方面没有限制。Decimal128的最大值约为10^6145,最小值约为-10^6145,最大精度为 34 位。Decimal128能够接受带符号的NaN值,而BigDecimal不能。 所有反序列化为BigDecimal实例的带符号NaN值都将是无符号的。Decimal128在序列化到 BSON 和从 BSON 反序列化时保留尾随零。 但是,BigDecimal不保留尾随零,因此使用BigDecimal可能会导致精度不足。
注意
在BSON库 v5.0 中,默认下,Decimal128 反序列化为 BigDecimal。为了将BSON文档中的 Decimal128 值反序列化为 BSON::Decimal128,您可以在调用 from_bson 时设立mode: :bson 选项。
JSON 序列化
某些BSON 类型在JSON中具有特殊表示形式。 下表描述了当您对指定类型调用 to_json 时的序列化行为。
Ruby BSON对象 | JSON表示形式 |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
时间实例
Ruby中的时间具有纳秒精度。BSON中的时间具有毫秒精度。当您将Ruby Time 实例序列化为BSON或扩展JSON时,时间将四舍五入到最接近的毫秒。
注意
时间值向下四舍五入。如果时间早于 Unix 纪元(一月 1, 1970 00:00:00 UTC),则时间的绝对值会增加:
time = Time.utc(1960, 1, 1, 0, 0, 0, 999_999) time.to_f # => -315619199.000001 time.floor(3).to_f # => -315619199.001
由于这种舍入行为,我们建议您使用整数数学来执行所有时间计算,因为点计算的不精确性可能会产生意外的结果。
注意
JRuby 9.2.11.0将 Unix 之前的纪元时间向上舍入而不是向下舍入。要学习;了解有关此行为的更多信息,请参阅相关的Github问题。BSON库纠正了这一行为,并降低了在 JRuby 上进行序列化的时间。
DateTime 实例
BSON支持将时间值存储为自 Unix 纪元以来的秒数。Ruby DateTime 实例可序列化为BSON,但反序列化BSON时,时间将作为 Time 实例返回。
Ruby中的 DateTime 类支持非公历。序列化非公历 DateTime 实例时,它们首先会转换为公历,并将公历中的相应日期存储在数据库中。
日期实例
BSON支持将时间值存储为自 Unix 纪元以来的秒数。Ruby Date 实例可序列化为BSON,但反序列化BSON时,时间将作为 Time 实例返回。
序列化 Date 实例时,使用的时间值为 UTC 的 Date 午夜。
正则表达式
MongoDB和Ruby都支持使用正则表达式,但它们使用正则表达式引擎。以下小节详细介绍了Ruby正则表达式和MongoDB正则表达式之间的区别。
MongoDB正则表达式
MongoDB使用通过 PCRE 库实现的与 Perl 兼容的正则表达式。Ruby正则表达式是使用Onigmo正则表达式引擎实现的,该引擎是Oniguruma库的一个分支。
这两个正则表达式实现通常提供相同的功能,但有几个重要的语法差异,以下各节将对此进行描述。
没有简单的方法以编程方式将 PCRE 正则表达式转换为等效的Ruby正则表达式,因为目前没有针对 PCRE 的Ruby绑定。
选项、标志和修饰符
Ruby和 PCRE 正则表达式都支持修饰符。在Ruby上下文中也称为“选项”,在 PCRE 上下文中也称为“标志”。s 和 m 修饰符在Ruby和 PCRE 中的含义有以下不同:
Ruby没有
s修饰符。相反, Rubym修饰符执行与 PCREs修饰符相同的功能,即使句点 (.) 匹配包括换行符在内的任何字符。Ruby文档将m修饰符称为启用多行模式。Ruby 始终以与 PCRE 的多行模式等效的方式运行,该模式由 PCRE 正则表达式中的
m修饰符启用。 在 Ruby 中,^锚点始终指行首,$锚点始终指行尾。
在编写要在Ruby和 PCRE 环境(包括MongoDB Server和大多数其他MongoDB驱动程序)中使用的正则表达式时,请避免使用 ^ 和 $ 锚点。以下部分提供了创作可在多个上下文中使用的可移植正则表达式的变通方法和建议。
^ 锚点
在Ruby正则表达式中,^ 锚点始终指行首。在 PCRE 正则表达式中,^ 锚点默认默认输入的开头,m 标志将其含义更改为行的开头。
Ruby和 PCRE 正则表达式都支持\A 锚点来引用输入的开头,而与修饰符无关。以下建议允许您写入可移植的正则表达式:
使用
\A锚点来引用输入的开头。如果在 PCRE 正则表达式中设立了
m标志,请使用^锚点来引用行首。或者,使用以下构造之一,无论修饰符如何,该构造都有效:(?:\A|(?<=\n)):处理LF和CR+LF行尾(?:\A|(?<=[\r\n])):处理CR、LF和CR+LF行尾
$ 锚点
在 Ruby 正则表达式中, $锚点始终指代行尾。 在 PCRE 正则表达式中, $锚点默认指输入的末尾,而m标志会将其含义更改为行尾。
Ruby 和 PCRE 正则表达式都支持\z锚点来引用输入结束,而与修饰符无关。
以下建议允许您写入可移植的正则表达式:
使用
\z锚点来引用输入的结尾。如果在 PCRE 正则表达式中设立了
m标志,请使用$锚点来引用行首。或者,使用以下构造之一,无论修饰符如何,该构造都有效:(?:\z|(?=\n)):处理LF和CR+LF行尾(?:\z|(?=[\n\n])):处理CR、LF和CR+LF行尾
BSON::Regexp::Raw
由于没有简单的方法以编程方式将 PCRE 正则表达式转换为等效的Ruby正则表达式,因此BSON库提供了 BSON::Regexp::Raw 类来存储 PCRE 正则表达式。
您可以使用字符串形式的正则表达式文本和可选的 PCRE 修饰符来创建 BSON::Regexp::Raw 实例:
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">
BSON::Regexp 模块包含在Ruby Regexp 类中,因此可以省略 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">
正则表达式转换
以下代码将Ruby正则表达式转换为 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>
BSON::Regexp::Raw 构造函数接受Ruby数字选项和 PCRE 修饰符字符串。
要将 BSON 正则表达式转换为 Ruby 正则表达式,请对 BSON 正则表达式调用compile方法:
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/
在前面代码的第一个示例中,s PCRE 修饰符被转换为 m Ruby修饰符,而最后两个示例被转换为相同的正则表达式,即使原始BSON正则表达式具有不同的含义。
当 BSON 正则表达式使用不可移植的^和$锚点时,到 Ruby 正则表达式的转换可能会改变其含义:
BSON::Regexp::Raw.new("^hello.world", "").compile =~ "42\nhello world" # => 3
当Ruby正则表达式转换为BSON正则表达式时(示例作为查询的一部分), BSON正则表达式始终设立m 修饰符,反映Ruby正则表达式中 ^ 和 $ 锚点的行为。
读取和写入正则表达式
Ruby和BSON正则表达式实现了用于序列化为BSON的 to_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"
Regexp 和 BSON::Regexp::Raw 类都实现了from_bson 类方法,该方法从BSON字节缓冲区反序列化正则表达式。这两个类的方法都会返回一个 BSON::Regexp::Raw实例,必须使用 compile 方法将该实例转换为Ruby正则表达式,如前面的代码中所述。
以下代码演示了如何使用 from_bson 方法反序列化正则表达式:
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/
键顺序
BSON文档会保留键的顺序,因为文档会存储为键值对列表。Ruby中的哈希还会保留键顺序,因此当您将哈希序列化为BSON文档以及将BSON文档反序列化为哈希时,应用程序中指定的键顺序都会保留。
重复键
BSON规范允许BSON文档具有重复键,因为文档存储为键值对列表。避免创建包含重复键的文档,因为当BSON文档包含重复键时, MongoDB Server 的行为是未定义的。
在Ruby中,哈希不能有重复的键。将Ruby哈希序列化为BSON文档时,不会生成重复键。
由于BSON文档中的键始终存储为字符串,因此指定与Ruby中的字符串和符号相同的键仅保留最新的规范:
BSON::Document.new(test: 1, 'test' => 2) # => {"test"=>2}
加载具有重复键的 BSON 文档时,重复键的最后一个值会覆盖同一键的先前值。