Docs 菜单
Docs 主页
/ / /
Ruby MongoDB 驱动程序
/

BSON 教程

在此页面上

  • 安装
  • 与 ActiveSupport 一起使用
  • BSON 序列化
  • 字节缓冲区
  • 写作
  • 读取
  • 支持的类
  • BSON::Binary
  • BSON::Code
  • BSON::CodeWithScope
  • BSON::DBRef
  • BSON::Document
  • BSON::MaxKey
  • BSON::MinKey
  • BSON::ObjectId
  • BSON::Timestamp
  • BSON::Undefined
  • BSON::Decimal128
  • Symbol
  • JSON 序列化
  • 时间实例
  • DateTime 实例
  • 日期实例
  • 正则表达式
  • Ruby 与 MongoDB 正则表达式
  • BSON::Regexp::Raw
  • 正则表达式转换
  • 读取和写入
  • 键顺序
  • 重复键

本教程讨论如何使用 Ruby BSON 库。

可以从 Rubygems 安装BSON库 手动或使用捆绑器。

要手动安装 gem:

gem install bson

要使用捆绑器安装 gem,请在 Gemfile中包含以下内容:

gem 'bson'

BSON 库与 MRI >= 2.5 和 JRuby >= 9.2 兼容。

默认情况下,不会加载 ActiveSupport 定义的类(例如 TimeWithZone)的序列化,以避免 BSON 对 ActiveSupport 的硬依赖。 在也使用 ActiveSupport 的应用程序中使用 BSON 时,必须明确要求 ActiveSupport 相关代码:

require 'bson'
require 'bson/active_support'

通过在 Ruby 对象上调用to_bson来获取 Ruby 对象的原始 BSON 表示,这将返回BSON::ByteBuffer 。 例如:

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

要从 BSON 生成对象,请对要实例化的类调用from_bson并向其传递BSON::ByteBuffer实例。

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

BSON 库 4.0 引入在 MRI 和 JRuby 中使用原生字节缓冲区,而不是使用StringIO ,以提高性能。

要创建用于写入的ByteBuffer (即 序列化为 BSON),实例化不带参数的BSON::ByteBuffer

buffer = BSON::ByteBuffer.new

要将原始字节写入字节缓冲区而不进行转换,请使用put_byteput_bytes方法。 它们将字节字符串作为参数并将该字符串复制到缓冲区中。 put_byte强制该参数为长度为 1 的字符串; put_bytes接受任意长度的字符串。 字符串可以包含 null 字节。

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

注意

put_byteput_bytes在将参数写入字节缓冲区之前不写入 BSON 类型字节。

后续写入方法写入 BSON 规范 中特定类型的对象 。请注意,方法名称指示的类型优先于参数的类型,例如,如果将浮点值赋予put_int32 ,则会将其强制转换为整数,并将生成的整数写入字节缓冲区。

要将 UTF-8 字符串(BSON 类型 0x02)写入字节缓冲区,请使用put_string

buffer.put_string("hello, world")

请注意,BSON 字符串始终以 UTF-8 编码。 因此,该参数必须采用 UTF-8 格式或可转换为 UTF-8 的编码格式(即 非二进制)。 如果参数采用的编码不是 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_int32put_int64方法。 请注意,Ruby 整数可以是任意大;如果写入的值超出 32 位或 64 位整数的范围,则put_int32put_int64会引发RangeError

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

注意

如果put_int32put_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) # a read mode buffer.

从缓冲区读取数据是通过以下 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.

要从缓冲区的开头重新开始读取,请使用rewind

buffer.rewind

注意

ByteBuffer 分别追踪读取和写入位置。rewind仅影响读取位置。

在 BSON 规范中具有表示形式并将具有为其定义的to_bson方法的核心 Ruby 类是: ObjectArrayFalseClassFloatHashIntegerBigDecimalNilClassRegexpStringSymbol (已弃用)、 TimeTrueClass

除了核心 Ruby 对象之外,BSON 还提供了一些特定于规范的特殊类型:

使用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:user

可以使用datatype属性从Binary实例中检索数据和子类型,如下所示:

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

注意

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>

要从符合 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_uuidto_uuid方法时,可以显式指定标准表示形式:

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

请注意, :standard表示形式只能与子类型为:uuid (而非:uuid_old )的二进制文件一起使用。

存储在子类型 3 ( :uuid_old ) 的 BSON::Binary 对象中的数据可以按三种不同字节顺序之一持久保存,具体取决于创建数据的驱动程序。 字节顺序为 CSharp 传统、Java 传统和 Python 传统。 Python 旧版字节顺序与标准 RFC 4122 字节顺序相同; C# 旧版字节顺序和 Java 旧版字节顺序交换了一些字节。

包含旧版 UUID 的二进制对象不会对 UUID 的存储格式进行编码。因此,与旧版 UUID 格式相互转换的方法将所需的格式或表示形式作为参数。应用程序可以复制旧版 UUID 二进制对象,而不知道它们以哪种字节顺序存储数据。

提供了以下处理旧版 UUID 的方法,以便与以旧版 UUID 格式存储数据的现有部署实现互操作性。建议新应用程序仅使用:uuid (子类型 4)格式,该格式符合 RFC 4122。

要将旧版 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"

表示 JavaScript 代码的字符串。

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

注意

从 MongoDB 4.2.1 开始, CodeWithScope类型已弃用。 从 MongoDB 4.4 开始,各种服务器命令和操作符(例如$where )已删除对CodeWithScope的支持。 使用 MongoDB 4.4 及更高版本时,请使用其他 BSON types 和操作符。

表示带有哈希值的 JavaScript 代码字符串。

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

这是BSON::Document的子类,为 DBRef 的collection、ID 和数据库提供访问器。

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

注意

BSON::DBRef 构造函数将验证给定的哈希值,如果不是有效的 DBRef,则会引发 ArgumentError。 如果提供的 DBRef 无效, BSON::ExtJSON.parse_objHash.from_bson不会引发错误,而是会解析哈希或反序列化 BSON::文档。

注意

如果所有 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

为了向后兼容 MongoDB Ruby 驱动程序版本 2.17 及更早版本,还可以使用旧版驱动程序 API 来构造BSON::DBRef 。 此 API 已弃用,并将在bson-ruby的未来版本中删除:

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

这是Hash的子类,它将所有键存储为字符串,但允许使用符号键访问它们。

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

注意

所有 BSON 文档都会反序列化为 BSON::文档(或 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 中的值,该值始终比另一个值更高。

BSON::MaxKey.new

表示 BSON 中的值,与另一个值相比,该值始终为较低值。

BSON::MinKey.new

表示给定计算机上对象的 12 字节唯一标识符。

BSON::ObjectId.new

表示具有起始值和增量值的特殊时间。

BSON::Timestamp.new(5, 30)

表示未提供的值的占位符。

BSON::Undefined.new

表示基于十进制的 128 位浮点值,能够以精确的精度模拟十进制舍入。

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

BigDecimal from_bsonto_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 5.0 中, decimal128默认反序列化为BigDecimal 。 为了将 BSON 文档中的decimal128值反序列化为BSON::Decimal128 ,可以在from_bson上设置mode: :bson选项。

BSON 规范定义了一种符号类型,允许往返 Ruby Symbol值(即 Ruby Symbol``is encoded into a BSON symbol and a BSON symbol is decoded into a Ruby ``Symbol )。 但是,由于大多数编程语言没有原生符号类型,为了促进互操作性,MongoDB 弃用了 BSON 符号类型,鼓励使用字符串。

注意

在 BSON 中,哈希始终是字符串。 非字符串值在用作哈希键时将被字符串化:

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

默认情况下,BSON 库将Symbol哈希值编码为字符串,并将 BSON 符号解码为 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}

要强制将 Ruby 符号编码为 BSON 符号,请将 Ruby 符号包装在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"

某些 BSON 类型在 JSON 中具有特殊表示形式。 它们如下所示,在对其调用to_json时会自动在表单中进行序列化。

对象
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" }

Ruby 中的时间可以达到纳秒精度。 BSON(和 MongoDB)中的时间只能具有毫秒精度。 当 Ruby Time实例序列化为 BSON 或扩展 JSON 时,时间将精确到毫秒。

注意

时间一如既往地四舍五入。 如果时间早于 Unix 纪元(UTC 时间 1970 年 1 月 1 日 00:00:00),时间的绝对值将增加:

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 之前的纪元时间向上舍入而不是向下舍入 。bson-Ruby 可以解决这个问题,并在 JRuby 上进行序列化时正确减少时间。

由于此下限,强烈建议应用程序使用整数数学来执行所有时间计算,因为浮点计算的不精确性可能会产生意外的结果。

BSON 仅支持将时间存储为自 Unix 纪元以来的秒数。 Ruby 的DateTime实例可以序列化为 BSON,但当反序列化 BSON 时,这些时间将作为Time实例返回。

DateTime Ruby 中的日历类支持非公历。 当非公历DateTime实例被序列化时,它们首先会转换为公历,并将公历中的相应日期存储在数据库中。

BSON 仅支持将时间存储为自 Unix 纪元以来的秒数。 Ruby 的Date实例可以序列化为 BSON,但当反序列化 BSON 时,这些时间将作为Time实例返回。

序列化Date实例时,使用的时间值是Date所指日期的午夜 (UTC)。

MongoDB 和 Ruby 都提供了使用正则表达式的工具,但它们使用正则表达式引擎。 以下小节详细介绍了 Ruby 正则表达式和 MongoDB 正则表达式之间的区别,并描述了如何使用两者。

MongoDB Server 使用 通过 PCRE 库实现的与 Perl 兼容的正则表达式 Ruby 正则表达式 使用 Onigmo 正则表达式引擎 实现 ,这是 Oniguruma 的一个分支 。这两个正则表达式实现通常提供相同的功能,但有几个重要的语法差异,如下所述。

遗憾的是,没有简单的方法可以以编程方式将 PCRE 正则表达式转换为等效的 Ruby 正则表达式,并且当前没有针对 PCRE 的 Ruby 绑定。

Ruby 和 PCRE 正则表达式都支持修饰符。 这些在 Ruby 中也称为“选项”,在 PCRE 中也称为“标志”。 sm修饰符在 Ruby 和 PCRE 中的含义有所不同:

  • Ruby 没有s修饰符,而 Ruby m修饰符执行与 PCRE s修饰符相同的功能,即使句点 ( . ) 匹配包括换行符在内的任何字符。 令人困惑的是,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 行尾)

由于没有简单的方法以编程方式将 PCRE 正则表达式转换为等效的 Ruby 正则表达式,因此 bson-Ruby 提供了BSON::Regexp::Raw类来保存 MongoDB/PCRE 正则表达式。 在本文档中,此类的实例称为“BSON 正则表达式”。

可以使用作为字符串的正则表达式文本和可选的 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">

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 正则表达式,请实例化一个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", "")
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 和 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"

RegexpBSON::Regexp::Raw类都实现了from_bson类方法,该方法从 BSON 字节缓冲区反序列化正则表达式。 这两个类的方法都会返回一个BSON::Regexp::Raw实例,必须使用compile方法将该实例转换为 Ruby 正则表达式,如上所述。

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 文档时,将遵循 Ruby 中指定的键顺序;而在将 BSON 文档反序列化为哈希时,文档中的键顺序将与哈希中的键顺序相匹配。

BSON 规范允许 BSON 文档具有重复键,因为文档存储为键值对列表。 应用程序应避免生成此类文档,因为当 BSON 文档包含重复键时,MongoDB Server的行为是未定义的。

由于在 Ruby 哈希中不能有重复键,因此当将 Ruby 哈希序列化为 BSON 文档时,不会生成重复键。 (在 Ruby 中仍然可以手工制作具有重复键的 BSON 文档,并且其他一些 MongoDB BSON 库可能允许创建具有重复键的 BSON 文档。)

请注意,由于 BSON 文档中的键始终存储为字符串,因此指定与 Ruby 中的字符串和符号相同的键仅保留最新的规范:

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

加载具有重复键的 BSON 文档时,重复键的最后一个值会覆盖同一键的先前值。

后退

常见错误