Go链接Mongo失败问题的分析与联想
如果需要了解Mongo的使用方法,可以参考这篇文章:《分布式NoSQL数据库——MongoDB》
前言
在使用go语言操作Mongo数据库时,出现了BUG。可是用的都是一套代码,之前的Mongo就没有出现过问题。以下是错误内容:
1 | err:server at 10.242.225.93:17085 reports wire version 5, but this version of the Go driver requires at least 6 (MongoDB 3.6 |
从错误中可以看到,显示的事wire的版本是5,而当前版本的Go驱动仅支持6版本以上(Mongo版本至少为3.6)
这里说明一下各个组件的版本:
- Golang:1.21.4
- Golang链接Mongo的驱动:go.mongodb.org/mongo-driver@v1.13.1
- Mongo数据库:3.4版本
引发的思考:
- wire是什么?与Mongo是什么关系?
- mongo-driver、wire、Mongo这三者之间的版本关联关系是什么?
Wire介绍
Wire Protocol(线协议)是MongoDB客户端与服务器之间通信的底层二进制协议
Wire主要决定了如下内容:
- 客户端如何向服务器发送请求
- 服务器如何向客户端返回响应
- 消息的格式、结构和编码方式
- 支持的操作类型(如插入、查询、更新等)
不同的Wire版本之间,新增了那些特性?下面表格式AI的总结:
| MongoDB 版本 | Wire Version | 发布时间 | 主要新特性 |
|---|---|---|---|
| 2.6 | 2 | 2014年 | 基础 CRUD 操作 |
| 3.0 | 3 | 2015年 | SCRAM-SHA1 认证 |
| 3.2 | 4 | 2015年 | OP_MSG 命令支持 |
| 3.4 | 5 | 2016年 | 聚合管道改进、$lookup 等 |
| 3.6 | 6 | 2017年 | OP_MSG 成为主要协议、会话支持 |
| 4.0 | 7 | 2018年 | 事务支持 |
| 4.2 | 8 | 2019年 | 分布式事务 |
| 4.4 | 9 | 2020年 | 流式聚合 |
| 5.0 | 13 | 2021年 | 时间序列集合 |
不同的GO驱动版本支持的Wire版本,AI的总结:
| 驱动版本 | 支持的 MongoDB 版本 | 最低 Wire Version | 说明 |
|---|---|---|---|
| v1.4.4 | MongoDB 3.4+ | 5 | 该版本是支持 MongoDB 3.4 的版本,最低要求 Wire Version 5 |
| v1.5.0 - v1.12.0 | MongoDB 3.4+ | 5 | 从 v1.4.4 到 v1.12.0 都支持 MongoDB 3.4+ |
| v1.13.0 - v1.15.0 | MongoDB 3.6+ | 6 | 从 v1.13.0 开始移除对 MongoDB 3.4 的支持 |
| v1.16.0+ | MongoDB 4.2+ | 8 | 最新版本支持 MongoDB 4.2+,Wire Version 8+ |
Mongo的底层数据
从上面的Wire协议介绍中发现,Wire决定了消息的格式、结构和编码方式,那么使用不同的Wire版本,查询出来的数据就会不同(注意:这里说的数据不是反序列化后的数据,而是二进制数据)
为什么要确认这种情况?
在Go使用Mongo的场景下,经常会有数据的字段未能保持一致(虽然Mongo3.2+增加了Schema,但是还是有人未做限制,针对于Schema,后面会详细介绍),这时,通常需要开发者自己手动转化。在GO查询的过程中,可以使用下面这种方式,来对查询出来的字段的字节码进行自定义转化
1 | type FieldAValue struct { |
而在Wire 5的版本中,针对int类型、string类型的数据,则无法使用bson.Unmarshal(data, &modelStr)的方法进行转义,因为他们的数据结构不同。以下是Wire 5 中的数据格式(即data值):
1 | numberInt(0):00 00 00 00 (4字节) |
Mongo的Schema验证
Mongo3.2+的版本中,增加了对集合字段的约束,被称为“Schema”。使用这一特性,我们就可以对写入到集合中的数据做验证,不仅能保证字段的类型一致,还可以保证枚举值、范围值等符合要求
查询验证规则
1 | db.getCollectionInfos({ |
- 结果(脱敏后的数据)
1 | [ |
options.validator字段就是该集合的Schema验证规则
创建验证规则
1 | // 示例:创建 "users" 集合,限制字段类型和约束 |
更新验证规则
1 | db.runCommand({ |
常用的约束关键字
| 关键字 | 作用 | 示例值 |
|---|---|---|
| bsonType | 限制字段的 BSON 类型(核心) | string、int、bool、date |
| required | 标记字段为必填(数组形式,包含字段名) | ["name", "age"] |
| minimum/maximum | 限制数字类型的范围(仅对 int/double 有效) | minimum: 0、maximum: 120 |
| minLength/maxLength | 限制字符串长度 | minLength: 2、maxLength: 20 |
| pattern | 限制字符串匹配正则表达式 | ^[a-zA-Z0-9]+$(字母数字) |
| enum | 限制字段值只能是枚举列表中的元素 | ["male", "female", "other"] |
| anyOf | 指定一个字段可以匹配多个的任意一个 | [{"bsonType":"string"},{"bsonType":"int"}] |
| items | 用于定义数组类型字段中元素 | |
| description | 描述信息 | |
| validationLevel | 指定数据在更新或插入文档时的验证级别 | "strict"、"moderate"、"off" |
| validationAction | 指定当文档违反验证规则时采取的操作 | "error"、"warn" |