- 后端
- 数据库
- 文档数据库
【免费下载链接】FerretDB
A truly Open Source MongoDB alternative
本指南将带你完整走一遍"以 Aiven 托管 PostgreSQL 为后端、以 FerretDB 为兼容层、以 MongoDB 原生工具连接"的云上部署流程:从创建 Aiven for PostgreSQL 服务、准备数据库,到通过 Docker 启动 FerretDB 并配置FERRETDB_POSTGRESQL_URL连接串,再到用mongosh执行插入、查询、比较运算与排序等真实 MongoDB 操作,最后用psql直接查看数据在 PostgreSQL 中如何以 JSONB 存储。读完本文,你将掌握一套可复制、可上生产环境的 MongoDB 到开源替代方案的迁移与运行方案。
对于希望摆脱 MongoDB 授权与锁定、又不想放弃现有 MongoDB 工具链的团队而言,FerretDB 是一个真正的开源 MongoDB 替代方案:它把 MongoDB 客户端发出的请求翻译成 SQL,并让数据落盘在 PostgreSQL 之上。而 Aiven for PostgreSQL 则提供了一个统一、云厂商无关的托管平台,涵盖 PostgreSQL 扩展、高可用与性能、以及与既有数据基础设施的集成能力。两者结合,即可让 MongoDB 工作负载平稳运行在云上托管的 PostgreSQL 之上。
前提条件
开始之前,请确保具备以下环境:
- Aiven 账号
psql(PostgreSQL 命令行客户端)- Docker
mongosh(MongoDB Shell)
其中mongosh用于以标准 MongoDB 方式连接和操作 FerretDB,psql用于验证数据在后端 PostgreSQL 中的实际落盘形态,两者在本教程中都会用到。
第一步:创建并准备 Aiven for PostgreSQL 服务
如果你还没有 Aiven 账号,请先注册一个。登录 Aiven 控制台后,从仪表盘创建一个 PostgreSQL 服务。
服务创建完成后,你会获得一个形如下面的 PostgreSQL 连接串:
postgres://<username>:<password>@<host>:<port>/<database>?sslmode=require注意连接串末尾的sslmode=require:Aiven 托管服务默认启用 TLS 加密连接,FerretDB 与 PostgreSQL 后端之间的链路同样需要走 TLS,这一点务必保留。
接下来,用psql连接到该连接串,并创建一个名为ferretdb的数据库,用于存放 FerretDB 的数据:
defaultdb=> CREATE DATABASE ferretdb OWNER <username>; CREATE DATABASE将<username>替换为你的 Aiven PostgreSQL 用户。之所以显式指定OWNER,是为了确保 FerretDB 后续能以该用户身份在该数据库内自由建表、读写数据。
第二步:通过 Docker 启动 FerretDB
启动 FerretDB 时,需要告知它后端 PostgreSQL 的地址。有两种等价的配置方式:
- 环境变量:
FERRETDB_POSTGRESQL_URL - 命令行参数:
--postgresql-url
在源码层面,cmd/ferretdb/main.go 中通过kong框架定义了该参数:--postgresql-url的默认值为postgres://127.0.0.1:5432/postgres,并支持--postgresql-url-file从文件读取连接串(若指定则覆盖前者)。同时kong.DefaultEnvars("FERRETDB")让所有参数都可以用FERRETDB_前缀的环境变量覆盖,因此FERRETDB_POSTGRESQL_URL与--postgresql-url完全等价,按需选用即可。
使用 Docker 运行如下命令:
docker run -e FERRETDB_POSTGRESQL_URL='postgres://<username>:<password>@<host>:<port>/ferretdb?sslmode=require' -p 27017:27017 ghcr.io/ferretdb/ferretdb请注意替换<username>、<password>、<host>和<port>为你实际的 Aiven 凭据与连接信息,并确保数据库名指向上一步创建的ferretdb。这里把 FerretDB 的 MongoDB 协议监听端口27017映射到宿主机,-p 27017:27017之后,本地客户端即可直接访问。
启动成功后,用mongosh以 MongoDB URI 格式连接 FerretDB:
mongosh 'mongodb://<username>:<password>@127.0.0.1:27017/ferretdb?authMechanism=PLAIN'这里有几个关键点:
authMechanism=PLAIN:FerretDB 使用 PLAIN 认证机制,用户名密码会透传给后端 PostgreSQL 完成身份校验(仓库内其他部署文档,如 website/blog/2023-06-26-configure-ferretdb-work-percona-distribution-postgresql.md,均使用同一 URI 规范);- URI 中的用户名/密码应与 Aiven PostgreSQL 用户一致;
- 连接地址是
127.0.0.1:27017,即本地映射的 FerretDB 端口,而非直接连接 Aiven 主机。
至此,FerretDB 已就绪,可以开始执行各种 MongoDB 操作了。
第三步:在 FerretDB 上执行 MongoDB 操作
下面以一个天文数据集为例:astronomy集合中存放了若干恒星的名称、类型、质量、直径、所属星座与距地距离。
插入数据(insertMany)
db.astronomy.insertMany([ { name: 'Alpha Centauri A', type: 'Star', distance_from_earth: 4.37, mass: 2.187e30, diameter: 1214000, constellation: 'Centaurus' }, { name: 'Alpha Centauri B', type: 'Star', distance_from_earth: 4.37, mass: 1.804e30, diameter: 865000, constellation: 'Centaurus' }, { name: 'Proxima Centauri', type: 'Star', distance_from_earth: 4.24, mass: 2.446e29, diameter: 200000, constellation: 'Centaurus' }, { name: 'Betelgeuse', type: 'Star', distance_from_earth: 642.5, mass: 2.78e31, diameter: 1.2e9, constellation: 'Orion' }, { name: 'Vega', type: 'Star', distance_from_earth: 25.04, mass: 4.074e30, diameter: 2440000, constellation: 'Lyra' } ])执行后,astronomy集合中包含 5 个文档,分别记录不同恒星的质量、直径与距地距离。其中质量的单位是千克(kg),直径单位是千米(km),距地距离单位是光年(ly)。
查询数据(find + 等值匹配)
查询位于Centaurus(半人马座)星座中的恒星:
ferretdb > db.astronomy.find({ constellation: 'Centaurus' }) [ { _id: ObjectId('665f00fb2d149942b1b2b4b6'), name: 'Alpha Centauri A', type: 'Star', distance_from_earth: 4.37, mass: 2.187e30, diameter: 1214000, constellation: 'Centaurus' }, { _id: ObjectId('665f00fb2d149942b1b2b4b7'), name: 'Alpha Centauri B', type: 'Star', distance_from_earth: 4.37, mass: 1.804e30, diameter: 865000, constellation: 'Centaurus' }, { _id: ObjectId('665f00fb2d149942b1b2b4b8'), name: 'Proxima Centauri', type: 'Star', distance_from_earth: 4.24, mass: 2.446e29, diameter: 200000, constellation: 'Centaurus' } ]返回 3 条结果:Alpha Centauri A、Alpha Centauri B 与 Proxima Centauri。注意每条文档都被自动分配了_id(ObjectId),这正是 MongoDB 的典型行为。
使用运算符查询($lt 比较运算)
接下来找出质量小于1e30kg 的恒星:
ferretdb > db.astronomy.find({ mass: { $lt: 1e30 } }) [ { _id: ObjectId('665f00fb2d149942b1b2b4b8'), name: 'Proxima Centauri', type: 'Star', distance_from_earth: 4.24, mass: 2.446e29, diameter: 200000, constellation: 'Centaurus' } ]只有 Proxima Centauri 满足条件——它的质量2.446e29kg 是唯一小于1e30的。这说明 FerretDB 对 MongoDB 查询运算符(如$lt)具备原生支持,使用体验与 MongoDB 保持一致。
排序(sort)
还可以按距地距离对文档排序:
ferretdb > db.astronomy.find({}).sort({ distance_from_earth: 1 }) [ { _id: ObjectId('665f00fb2d149942b1b2b4b8'), name: 'Proxima Centauri', type: 'Star', distance_from_earth: 4.24, mass: 2.446e29, diameter: 200000, constellation: 'Centaurus' }, { _id: ObjectId('665f00fb2d149942b1b2b4b6'), name: 'Alpha Centauri A', type: 'Star', distance_from_earth: 4.37, mass: 2.187e30, diameter: 1214000, constellation: 'Centaurus' }, { _id: ObjectId('665f00fb2d149942b1b2b4b7'), name: 'Alpha Centauri B', type: 'Star', distance_from_earth: 4.37, mass: 1.804e30, diameter: 865000, constellation: 'Centaurus' }, { _id: ObjectId('665f027e2d149942b1b2b4ba'), name: 'Vega', type: 'Star', distance_from_earth: 25.04, mass: 4.074e30, diameter: 2440000, constellation: 'Lyra' }, { _id: ObjectId('665f027e2d149942b1b2b4b9'), name: 'Betelgeuse', type: 'Star', distance_from_earth: 642.5, mass: 2.78e31, diameter: 1200000000, constellation: 'Orion' } ]结果按距地距离升序排列:最近的 Proxima Centauri(4.24 ly)排在最前,最远的 Betelgeuse(642.5 ly)排在最后。可以看到,FerretDB 不仅支持简单的等值查询,还能完整处理 MongoDB 的比较运算符与排序语义。
第四步:用 psql 查看 PostgreSQL 中的数据
FerretDB 的价值在于:你既可以享受 MongoDB 的开发体验,又可以把数据完整地托管在 PostgreSQL 中,从简单查询到复杂聚合皆可。那么这些数据在 Postgres 里长什么样?通过psql连接后端即可一探究竟。
ferretdb=> SET SEARCH_PATH to ferretdb; SET ferretdb=> \dt List of relations Schema | Name | Type | Owner ----------+-----------------------------+-------+---------- ferretdb | _ferretdb_database_metadata | table | avnadmin ferretdb | astronomy_5f9854f1 | table | avnadmin (2 rows) ferretdb=> SELECT * FROM astronomy_5f9854f1; _jsonb ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- {"$s": {"p": {"_id": {"t": "objectId"}, "mass": {"t": "double"}, "name": {"t": "string"}, "type": {"t": "string"}, "diameter": {"t": "int"}, "constellation": {"t": "string"}, "distance_from_earth": {"t": "double"}}, "$k": ["_id", "name", "type", "distance_from_earth", "mass", "diameter", "constellation"]}, "_id": "665f00fb2d149942b1b2b4b6", "mass": 2187000000000000000000000000000, "name": "Alpha Centauri A", "type": "Star", "diameter": 1214000, "constellation": "Centaurus", "distance_from_earth": 4.37} {"$s": {"p": {"_id": {"t": "objectId"}, "mass": {"t": "double"}, "name": {"t": "string"}, "type": {"t": "string"}, "diameter": {"t": "int"}, "constellation": {"t": "string"}, "distance_from_earth": {"t": "double"}}, "$k": ["_id", "name", "type", "distance_from_earth", "mass", "diameter", "constellation"]}, "_id": "665f00fb2d149942b1b2b4b7", "mass": 1804000000000000000000000000000, "name": "Alpha Centauri B", "type": "Star", "diameter": 865000, "constellation": "Centaurus", "distance_from_earth": 4.37} {"$s": {"p": {"_id": {"t": "objectId"}, "mass": {"t": "double"}, "name": {"t": "string"}, "type": {"t": "string"}, "diameter": {"t": "int"}, "constellation": {"t": "string"}, "distance_from_earth": {"t": "double"}}, "$k": ["_id", "name", "type", "distance_from_earth", "mass", "diameter", "constellation"]}, "_id": "665f00fb2d149942b1b2b4b8", "mass": 244600000000000000000000000000, "name": "Proxima Centauri", "type": "Star", "diameter": 200000, "constellation": "Centaurus", "distance_from_earth": 4.24} {"$s": {"p": {"_id": {"t": "objectId"}, "mass": {"t": "double"}, "name": {"t": "string"}, "type": {"t": "string"}, "diameter": {"t": "int"}, "constellation": {"t": "string"}, "distance_from_earth": {"t": "double"}}, "$k": ["_id", "name", "type", "distance_from_earth", "mass", "diameter", "constellation"]}, "_id": "665f027e2d149942b1b2b4b9", "mass": 27800000000000000000000000000000, "name": "Betelgeuse", "type": "Star", "diameter": 1200000000, "constellation": "Orion", "distance_from_earth": 642.5} {"$s": {"p": {"_id": {"t": "objectId"}, "mass": {"t": "double"}, "name": {"t": "string"}, "type": {"t": "string"}, "diameter": {"t": "int"}, "constellation": {"t": "string"}, "distance_from_earth": {"t": "double"}}, "$k": ["_id", "name", "type", "distance_from_earth", "mass", "diameter", "constellation"]}, "_id": "665f027e2d149942b1b2b4ba", "mass": 4074000000000000000000000000000, "name": "Vega", "type": "Star", "diameter": 2440000, "constellation": "Lyra", "distance_from_earth": 25.04} (5 rows) (END)从\dt的输出可以看到两个关键的表:
_ferretdb_database_metadata:元数据表,记录数据库中的集合与对应物理表的映射关系;astronomy_5f9854f1:FerretDB 为astronomy集合自动创建的实际物理表。
而SELECT结果显示,每个 MongoDB 文档都被存为 JSONB 类型的一行数据(_jsonb列)。其中$s字段内的$k数组保存了字段顺序,$p中为每个字段记录了其原始 BSON 类型(objectId、double、string、int),而数值则以 JSON 数字形式存储。这种以$前缀标记类型信息的格式正是 FerretDB 的 PJSON 映射方案——它在 website/blog/2022-11-08-pjson-how-to-store-bson-in-jsonb.md 中有详细介绍:FerretDB 将 MongoDB 的 BSON 文档反序列化后映射为 PJSON,再存入 PostgreSQL 的 JSONB 列,从而既保留了 BSON 的类型信息与字段顺序,又充分利用了 JSONB 的查询与索引能力。
顺带一提,仓库根目录的 docker-compose.yml 中已包含一套本地开发用的postgres(以及yugabytedb、mongodb等)服务定义,如果你希望先在本地验证同样的流程,也可以参照该文件快速起一个 PostgreSQL 后端。
结语
PostgreSQL 是当今应用最广泛的开源数据库之一,而 Aiven for PostgreSQL 又为其提供了托管、高可用与多云能力。以 Aiven for PostgreSQL 为后端运行 FerretDB,你可以在几乎不改动应用代码的前提下,把 MongoDB 工作负载平稳迁移到完全开源的技术栈上——mongosh照常使用,查询运算符与排序语义完全兼容,同时数据以 JSONB 形态透明地托管在 PostgreSQL 中。
如果你打算正式启动从 MongoDB 到 FerretDB 的迁移,可以进一步阅读仓库中的迁移指南 website/docs/migration/migrating-from-mongodb.md,它基于mongodump/mongorestore与mongoexport/mongoimport等 MongoDB 原生工具,给出了完整的导出、导入与校验流程,帮助你以最小成本完成数据搬迁。
- 后端
- 数据库
- 文档数据库
【免费下载链接】FerretDB
A truly Open Source MongoDB alternative
相关推荐
在 Percona Distribution for PostgreSQL 上配置 FerretDB:Debian 包部署与 MongoDB 工作负载实战
在 Percona Distribution for PostgreSQL 上配置 FerretDB:Debian 包部署与 MongoDB 工作负载实战 本文
后端数据库文档数据库使用 KubeDB 托管 PostgreSQL 在 Kubernetes 上部署 FerretDB 实战指南
使用 KubeDB 托管 PostgreSQL 在 Kubernetes 上部署 FerretDB 实战指南 FerretDB 是一款开源文档数据库,它在 Po
后端数据库文档数据库使用 pgEdge 分布式 PostgreSQL 作为后端运行 FerretDB:从 Docker 部署到 MongoDB CRUD 实战
使用 pgEdge 分布式 PostgreSQL 作为后端运行 FerretDB:从 Docker 部署到 MongoDB CRUD 实战 FerretDB 是
后端数据库文档数据库
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考