MongoDB 3.6兼容性更新说明

本文介绍MongoDB 3.6版本的兼容性变化。

如需查看MongoDB官网兼容性更新说明文档,请前往MongoDB官网下载

本地主机绑定兼容性变更

MongoDB 3.6开始,MongoDBmongodmongos二进制文件,默认绑定到本地主机。若配置文件中设置了net.ipv6参数或通过命令行选项--ipv6启用了IPv6支持,程序会额外绑定到本地主机的IPv6地址。

MongoDB 2.6版本起,仅官方提供的RPM包(适用于Red Hat、CentOS、Fedora Linux及其衍生系统)和DEB包(适用于Debian、Ubuntu及其衍生系统)的二进制程序默认绑定到localhost。

当仅绑定到localhost时,MongoDB 3.6的这些程序仅接受来自同一台机器上客户端的连接(包括mongo shell、副本集的其他成员或分片集群的节点)。远程客户端将无法连接到仅绑定localhost的实例。

若需覆盖默认行为并绑定到其他IP地址,可通过配置文件中的net.bindIp参数或命令行选项--bind_ip指定主机名或IP地址列表。

重要

在绑定到非本地主机(例如公开可访问的IP地址)之前,请确保已对集群进行安全加固以防止未授权访问。至少应启用身份验证并强化网络基础设施。

例如,以下mongod实例绑定了本地主机与主机名My-Example-Associated-Hostname,后者与IP地址198.51.100.1相关联:

mongod --bind_ip localhost,My-Example-Associated-Hostname

为了连接到该实例,远程客户端必须指定主机名或其关联的IP地址198.51.100.1:

mongo --host My-Example-Associated-Hostname

mongo --host 198.51.100.1

分片集群

MongoDB 3.6版本起,分片(Shard)必须为副本集(Replica Set)。若要将分片集群升级到3.6版本,所有分片服务器必须以副本集形式运行。

HTTP接口与REST API

MongoDB 3.6版本起,HTTP接口及针对MongoDBREST API被正式移除。

配置

mongod/mongos选项

net.http.enabled

httpinterface

net.http.JSONPEnabled

nohttpinterface

net.http.port

jsonp

net.http.RESTInterfaceEnabled

rest

工具更新

MongoDB 3.6删除了mongooplog工具。

数组操作兼容性变更

$type: "array"行为变更

MongoDB 3.6版本起,type: "array"$type: 4表达式将匹配包含任意元素类型的数组字段。

3.6之前的版本中,$type: "array" 仅匹配包含嵌套数组的数组字段。

例如,集合 c 包含以下文档:

{ "_id": 1, "a": [ 1, 2, 3 ] },
{ "_id": 2, "a": [ 1, 2, [ 3, 4 ] ] }

以下操作通过字段 a 的类型进行查询:

db.c.find( { "a": { $type : "array" } } )

3.6版本开始,此查询将返回集合中的两个文档,因为 $type 查询现在能检测到字段 a 本身是数组:

{ "_id": 1, "a": [ 1, 2, 3 ] },
{ "_id": 2, "a": [ 1, 2, [ 3, 4 ] ] }

MongoDB 3.4及更早版本中,此查询仅返回字段 a 包含BSON数组类型元素的文档:

{ "_id": 2, "a": [ 1, 2, [ 3, 4 ] ] }

如果您当前的MongoDB实例版本为3.4.x并且正在使用partialFilterExpression包含$type: "array" 或 $type: 4的部分索引,则升级到3.6后必须重建这些索引,以避免因 $type: 'array' 语义变更引发冲突。

数组排序行为变更

MongoDB 3.6版本起,当对包含数组的字段进行排序时,MongoDB在升序排序中会以数组的最小元素值作为排序依据,降序排序则以数组的最大元素值为依据。排序时不再考虑查询谓词对数组元素的筛选。此行为变更适用于find命令和聚合管道操作。

当前依赖数组字段排序的应用程序可能会因该变更导致排序结果与之前版本不同。

说明

结合MongoDB 4.4版本对数组字段排序行为的进一步调整,若对使用多键索引的数组字段进行排序,查询计划将包含阻塞式排序阶段(blocking sort stage),除非满足以下条件:

  • 所有排序字段的索引边界为[MinKey, MaxKey]

  • 多键索引字段的边界路径前缀与排序模式无重叠。

find方法排序行为

MongoDB中,排序依据元素是指排序过程中用于比较含数组字段的文档时所选取的数组元素。升序排序时,数组内最小元素值作为排序依据的文档会优先排列;降序排序时则依据最大元素值。

不同版本的排序行为区别如下:

  • MongoDB 3.4及更早版本:对数组字段排序时,会结合查询条件筛选数组元素来确定排序依据。

  • MongoDB 3.6及之后版本:排序依据元素的选择不再考虑查询条件,仅基于数组本身的元素值。

升级至MongoDB 3.6后,若应用程序依赖数组字段排序且包含查询条件,需验证排序逻辑是否因行为变更受到影响,必要时调整代码以保证兼容性。

示例如下:

假设集合 coll 包含以下文档:

{ _id: 0, a: [-3, -2, 2, 3] }
{ _id: 1, a: [ 5, -4 ] }

执行针对数组字段 a 的查询与排序操作:

db.coll.find({a: {$gte: 0}}).sort({a: 1});
  • MongoDB 3.6中,排序依据元素为数组中最小值(忽略查询条件):

    • _id: 0 的数组 a 最小值是 -3。

    • _id: 1 的数组 a 最小值是 -4。

    返回结果为(按升序排列):

    { "_id" : 1, "a" : [ 5, -4 ] }
    { "_id" : 0, "a" : [ -3, -2, 2, 3 ] }
  • MongoDB 3.4及之前版本中,排序依据元素为匹配查询条件 {$gte: 0} 的最小元素:

    • _id: 0 的匹配元素为 [2, 3],取最小值 2。

    • _id: 1 的匹配元素为 [5],取最小值 5。

    返回结果为(按升序排列):

    { _id: 0, a: [-3, -2, 2, 3] }
    { _id: 1, a: [ 5, -4 ] }

聚合方法排序行为变更

MongoDB 3.6版本起,使用db.collection.aggregate()对数组字段排序时,仅以数组中的单个元素作为排序依据。

示例如下:

// Documents.
{ "_id" : 1, "timestamps" : [ ISODate("2017-07-15T15:31:01Z"), ISODate("2017-07-21T18:31:01Z") ] }
{ "_id" : 0, "timestamps" : [ ISODate("2017-07-21T15:31:01Z"), ISODate("2017-07-21T13:31:01Z") ] }

// Query.
db.c.aggregate([{$sort: {timestamps: -1}}])

MongoDB 3.6版本中:

  • 降序排序时,取数组中的最晚时间作为排序依据:

    • _id: 0 的数组取 72115:31。

    • _id: 1 的数组取 72118:31。

  • 结果按时间降序排列,文档 _id: 1(18:31)排在 _id: 0(15:31)之前。

3.6之前版本中,排序依据为整个数组逐元素比较。例如:

// Documents.
{_id: 0, a: [3, 1, 5]}
{_id: 1, a: [3, 4, 0]}

// Query.
db.coll.aggregate([{$sort: {a: 1}}])

3.6之前的版本中,排序依据为完整数组 [3,1,5] 与 [3,4,0]

  • 首元素相同(均为3),比较次元素:1 < 4

  • 结果文档 _id: 0 排在 _id: 1 之前。

聚合管道中对多数组字段的复合排序限制

MongoDB 3.6版本起,在聚合管道中进行排序时,若排序字段涉及并行数组(即排序字段为BSON对象中的同级数组元素),MongoDB无法完成排序。以下情况不视为并行数组:

  • 排序键为嵌套数组(例如字段路径包含层级关系)。

  • 排序键共享同一数组作为路径前缀。

说明

此限制在find命令中一直存在,但3.6版本后findaggregate的排序语义已统一。

  • 示例一:嵌套数组可排序

    集合包含文档如下:

    {a: [ {b: [1, 2]}, {b: [3, 4]} ]}

    执行以下聚合操作(排序键为嵌套数组字段):

    db.coll.aggregate([{$sort: {"a.b": 1}}])

    操作成功,因a.b为嵌套数组字段,不构成并行数组。

  • 示例二:共享相同数组前缀可排序

    集合包含文档如下:

    {a: [{b: 1, c: 1}, {b: 2, c: 2}]}

    执行以下聚合操作(排序键共享同一数组前缀):

    db.coll.aggregate([{$sort: {"a.b": 1, "a.c": 1}}])

    操作成功,因a.ba.c共享前缀a,不视为并行数组。

  • 示例三:同级数组导致排序失败

    集合包含文档如下:

    { _id: 1, a: [ 1, 2 ], b: [ 1, 2 ]}
    { _id: 2, a: [ -3, 5 ], b: 0 }
    { _id: 3, a: [ -6, 12 ], b: 100 }

    执行以下聚合操作(排序键为同级数组字段):

    db.coll.aggregate([ { $sort: {a: 1, b: 1} } ])

    由于文档_id: 1中字段ab为同级数组,构成并行数组,MongoDB无法完成排序导致报错。若需对多个数组字段进行复合排序,需确保排序字段为嵌套数组或共享同一数组前缀,且数据模型中应避免在同级字段中同时使用数组类型。

Update操作更新

新增字段的更新

MongoDB 3.6起,通过更新操作添加的新字段会按字典序(lexicographic order)追加。

例如,集合 coll 包含文档:

{ _id: 0, x: 0 }

执行更新操作添加两个新字段:

db.coll.update({_id: 0}, {$set: {b: 0, a: 0}})

3.6版本中,新字段按字典序追加,更新后文档为 {_id: 0, x: 0, a: 0, b: 0}

3.6之前的版本中,新字段按更新文档中的出现顺序追加,结果为 {_id: 0, x: 0, b: 0, a: 0}

arrayFilters标识符冲突的字段

MongoDB 3.6起,若字段名与arrayFilters的标识符语法(如 $[])冲突,则无法更新该字段。

例如,集合 coll 包含文档:

{ _id: 0, x: { "$[]": 0 } }

执行更新操作:

db.coll.update({_id: 0}, {$set: {"x.$[]": 1}})

3.6之前的版本中,更新操作将执行成功。在3.6版本中,因字段名 $[] 与arrayFilters语法冲突,将操作失败。

说明

此行为仅在 featureCompatibilityVersion(功能兼容版本)设为3.6时生效。

对$pop操作符实施更严格的验证

MongoDB 3.6起,$pop 操作符的参数必须以下值:

  • -1:移除数组的第一个元素。

  • 1:移除数组的最后一个元素。

3.6之前的版本中:

  • 任意负数均可移除首元素。

  • 任意非负数或非数值均可移除末尾元素。

移除$pushAll操作符

MongoDB 3.6移除了$pushAll 操作符(自2.4版起标记为弃用)。

请使用 $push + $each 操作符实现相同功能。示例如下:

db.students.update(
   { name: "joe" },
   { $push: { scores: { $each: [ 90, 92, 85 ] } } }
)

平台支持变更

  • MongoDB 3.6 停止对 Windows Server 2008 R2 及 Windows 7 之前版本的支持。

  • MongoDB 3.6 未针对 macOS 10.13 及更新版本采用的APFS(Apple文件系统)进行测试,在此类环境中运行时可能存在兼容性问题。

通用兼容性更新说明

弃用MONGODB-CR认证机制

MongoDB 3.6起,MONGODB-CR认证机制已被标记为弃用。若仍在使用MONGODB-CR认证模式,需立即升级至更安全的SCRAM认证。

仲裁节点(Arbiter)与优先级

所有仲裁节点(Arbiter)的优先级固定为 0。

弃用主从复制架构

MongoDB 3.6正式弃用主从复制(Master-Slave Replication)架构。

弃用WiredTiger存储引擎的--nojournal选项

3.6版本中,对使用WiredTiger存储引擎的副本集成员,弃用--nojournal选项,以避免产生数据风险。

调整aggregate命令及返回结果

MongoDB 3.6起,aggregate命令不再支持以单文档形式返回结果。

执行aggregate命令时,必须指定以下选项之一:

  • cursor:以游标形式返回结果(适用于大数据集)。

  • explain:返回聚合管道的执行计划分析。

建议您优先使用mongo shell中的db.collection.aggregate(),或对应驱动程序的等效方法。除非使用explain选项,否则这些方法默认返回游标。

变更聚合中日期转字符串格式

MongoDB 3.6版本起,在聚合表达式中将日期类型强制转换为字符串时,结果将包含毫秒级精度,并以字母 'Z' 结尾(表示UTC时区)。

示例如下:

// Documents.
{_id: 0, d: ISODate("2017-10-18T20:04:27.978Z")}
{_id: 1, d: ISODate("2017-10-18T20:04:28.192Z")}

// Query.
db.coll.aggregate({$project: {d: {$toLower: "$d"}}})

MongoDB 3.6之前版本中,返回字符串格式为 "2017-10-18t20:04:27" 和 "2017-10-18t20:04:28"

MongoDB 3.6及之后版本中,返回字符串格式为 "2017-10-18t20:04:27.978z" 和 "2017-10-18t20:04:28.192z"(含毫秒及小写'z')。

受影响的聚合操作符包括:

  • $concat

  • $substr

  • $substrBytes

  • $substrCP

  • $strcasecmp

  • $toLower

  • $toUpper

移除诊断日志命令与选项

MongoDB 3.6移除了已弃用的 diagLogging 命令及 mongod --diaglog 选项。

替代方案:使用 mongoreplay 工具捕获、回放及分析发送到MongoDB部署的命令。

validate操作变更

MongoDB 3.6版本起,仅当执行完整验证(full validation)时,validate 操作会强制触发检查点(checkpoint),将所有内存数据刷盘后再验证磁盘数据。

3.6之前的版本中,无论验证模式如何,均强制触发检查点。

当您使用 validate 命令或 db.collection.validate() 方法时,需明确指定 {full: true} 以执行完整验证。

索引名称限制

MongoDB 3.6版本起:

  • 禁止创建名为 * 的索引:无法在创建索引时指定名称 *

  • 无法通过索引键删除名为 * 的索引:需直接通过索引名称删除。

在升级至MongoDB 3.6版本前,您需要:

  • 删除现有 * 索引:在升级前手动删除所有名为 * 的索引。

  • 重命名索引:若需保留索引,需先删除再重建并指定新名称。

弃用选项

3.6.1版本变更。

  • 弃用 snapshot 查询选项

    • MMAPv1存储引擎:改用 hint({ _id: 1 }) 确保查询期间文档不被重复返回(即使中间写入导致文档移动)。

    • 其他存储引擎(如WiredTiger):改用 hint({ $natural: 1 })

  • 弃用 $isolated 操作符

    • 替代方案:通过事务或调整读写关注(read concern)实现隔离性。

不向后兼容的特性说明

以下MongoDB 3.6版本新特性需将featureCompatibilityVersion设为"3.6"后方可启用:

  • 集合UUID:每个集合拥有唯一标识符。

  • $jsonSchema文档验证:支持JSON Schema格式的文档结构校验。

  • 变更流(Change Streams):实时监控数据变更事件。

  • 分片感知的从节点(Chunk Aware Secondaries):优化分片集群中从节点的数据同步。

  • 视图定义、文档验证器及部分索引过滤器:若使用3.6新增的查询功能,需启用此配置。

  • 会话与可重试写入(Sessions & Retryable Writes):支持事务会话及写入操作自动重试。

  • 用户与角色的认证限制(Authentication Restrictions):精细控制用户权限。

featureCompatibilityVersion默认值如下:

您可以使用命令 db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } ) 查看当前featureCompatibilityVersion值。

若需从MongoDB 3.6版本降级至之前的版本,您必须清除所有不兼容数据(包括与会话、变更流、UUID集合等相关的持久化数据)。