今天给大家介绍一款开源文档数据库:FerretDB。它使用 PostgreSQL 作为数据库存储,兼容 MongoDB 6.0+ 协议,可以作为 MongoDB 一个开箱即用的替代产品。
⚠️由于 MongoDB 修改了它的开源协议(SSPL),导致很多开源软件和商用软件无法使用 MongoDB。
从原理上来讲,FerretDB 实现了一个无状态的代理,将 MongoDB 协议的查询转换为 SQL 语句,从而兼容 MongoDB 驱动。FerretDB 使用 GO 语言实现,遵循 Apache-2.0 开源协议,2023 年 4 月 11 日发布了第一个正式版本。
作为文档数据库,FerretDB 使用 BSON(二进制 JSON)存储数据,可以支持的数据类型比常规 JSON 更多,不过目前还不支持 128 位浮点数。
文档数据库中的集合(Collection)对应 PostgreSQL 中的表(Table),文档(Document)则对应行(Row)。对于文档数据库而言,插入数据之前不需要定义模式。因此很适合用于需要灵活模式的应用程序,例如博客、聊天应用、视频游戏等。
FerretDB 安装文件可以通过 Github 链接进行下载,目前只提供了 Docker、DEB 以及 RPM 安装包。
最简单的使用方式就是利用 Docker 镜像,例如:
docker run -d --rm --name ferretdb -p 27017:27017 ghcr.io/ferretdb/all-in-one
注意,默认的”all-in-one“镜像不适合生产环境,其它镜像类型包括 development 和 production,具体可以参考官方文档。
以上命令可以启动一个包括 FerretDB、PostgreSQL 以及 MongoDB Shell 的容器,可以用于测试和试验。
启动容器之后,我们可以:
mongodb://127.0.0.1:27017/
;mongosh
连接到 FerretDB,MongoDB Shell 可以使用以下命令进行安装:docker exec -it ferretdb mongosh
;docker exec -it ferretdb psql -U username ferretdb
。FerretDB 使用 PostgreSQL 模式作为 MongoDB 数据库。因此,如果我们使用 MongoDB 客户端在 test 数据库中创建了一些集合,就可以运行 PostgreSQL 命令SET search_path = 'test';
切换到该模式,并且利用 psql 命令\d
查看集合对应的数据表。停止容器的命令如下:
docker stop ferretdb
关于二进制包的安装,可以参考官方文档。
接下来我们介绍一些使用 FerretDB 时的基本 CURD 操作,它们和 MongoDB 中的文档操作相同。
以下方法可以用于创建新的文档。
db.collection.insertOne({field1: value1, field2: value2,.... fieldN: valueN})
db.collection_name.insertMany([{document1}, {document2},... {documentN}])
它们分别用于创建单个文档和多个文档。如果集合不存在,它们会先创建集合。
例如,以下示例为集合 scientists 创建了一个新的文档:
db.scientists.insertOne({
name: {
firstname: "Thomas",
lastname: "Edison"
},
born: 1847,
invention: "lightbulb"
})
{
acknowledged: true,
insertedId: ObjectId("6346fcafd7a4a1b0b38eb2db")
}
操作成功之后,返回 acknowledged 以及自动生成的文档 ID。
以下是一个创建多个文档的示例:
db.scientists.insertMany([
{
name: {
firstname: "Alan",
lastname: "Turing"
},
born: 1912,
invention: "Turing Machine"
},
{
name: {
firstname: "Graham",
lastname: "Bell"
},
born: 1847,
invention: "telephone"
},
{
name: {
firstname: "Ada",
lastname: "Lovelace"
},
born: 1815,
invention: "computer programming"
}
])
以下方法可以用于查询集合中的文档:
db.collection.find()
db.collection.findOne()
以下示例查询 scientists 集合中满足条件的第一个问题:
db.scientists.findOne({invention: "Turing Machine"})
find() 方法可以返回集合中的全部文档,例如:
db.scientists.find()
查询操作可以基于指定条件搜索文档,查询条件可以包含各种操作符($gt、$lt、$in 等),也可以查询数组或者嵌套文档。
以下方法可以用于更新文档:
db.collection.updateOne()
db.collection.updateMany()
db.collection.replaceOne()
例如,以下示例用于更新 firstname 字段等于“Graham”的文档,将其更新为“Alexander Graham”。updateOne() 方法只会更新满足条件的第一个文档。
db.scientists.updateOne({
firstname: "Graham"
},
{
$set:{
firstname: "Alexander Graham"
}
})
下面的示例使用 replaceOne() 方法替换整个文档:
db.scientists.replaceOne({
lastname: "Bell",
},
{
lastname: "Einstein",
firstname: "Albert",
born: 1879,
invention: "Photoelectric effect",
nobel: true
})
以下方法可以删除满足条件的文档:
db.collection.deleteOne()
db.collection.deleteMany()
例如,以下示例用于删除 nobel 字段为 false 的所有文档:
db.scientists.deleteMany({nobel:false})
FerretDB 目前存在一些和 MongoDB 不同的实现: