ITPub博客

首页 > 数据库 > 国内数据库 > 它以为自己连的是MongoDB

它以为自己连的是MongoDB

原创 国内数据库 作者:sjw1933 时间:2026-07-23 23:54:33 0 删除 编辑

前两天有幸拿到 KingbaseES V9R2C13(MongoDB兼容版)内测软件包,我第一件事是找台机器装上,然后把 Node.js 的 mongodb 驱动直接连过去。验证是否真的”兼容 MongoDB”。

环境是一台 Oracle Linux 8.10 x86 主机。软件放 /opt/kingbase/KingbaseES,数据放 /opt/kingbase/data,kingbase 用户跑库,systemd 管进程。


驱动用的是 mongodb@6.21.0。基础回归过了 19 个场景,深度探测过了 38 个。几组我心里没底的用例,另外在 MongoDB 7.0.28 上跑了同一份 Node.js 脚本,两边对返回值和数据变化。

关于安装

原厂 ISO,setup.sh -i console,一路装完。目录和权限按常规数据库服务的习惯来:软件目录 /opt/kingbase/KingbaseES,数据目录 /opt/kingbase/data,kingbase 用户运行数据库,systemd 负责服务启停和开机自启。


documentdb_core
documentdb
documentdb_extended_rum

代码还是熟悉的写法

驱动用 MongoDB URI 连接,认证方式按手册显式指定成 SCRAM-SHA-256。应用代码那边继续用 MongoClient、Db、Collection,没有额外包装。

const { MongoClient } = require(&#x27;mongodb&#x27;);const uri =  &#x27;mongodb://<user>:<password>@127.0.0.1:27017/test&#x27; +  &#x27;?authSource=admin&#x27; +  &#x27;&authMechanism=SCRAM-SHA-256&#x27; +  &#x27;&directConnection=true&#x27;;const client = new MongoClient(uri);await client.connect();const db = client.db(&#x27;test&#x27;);const users = db.collection(&#x27;users&#x27;);await users.insertOne({ name: &#x27;Alice&#x27;, tags: [&#x27;mongo&#x27;, &#x27;kingbase&#x27;] });console.log(await users.findOne({ name: &#x27;Alice&#x27; }));await client.close();

握手回来 hello.ok = 1,maxWireVersion = 21,buildInfo.version = 7.0.42。驱动那边认为自己连的是一个 7.0 的 MongoDB。后面所有集合创建、文档写入、查询和更新,都在这个连接上做完。

BSON 和文档操作

先测的是 ObjectId、Date、Binary、Decimal128、数组和嵌套文档的写入与读取。深度用例还专门塞了 4MB 的文档和 50 层嵌套的文档,读回来核对长度和层级。

查询覆盖了范围条件、逻辑条件、数组匹配、$exists、$type、$regex 和 $expr。排序、分页、投影、计数、distinct 也都进了回归脚本。

更新这块用例最多:$inc、$mul、$min、$max、$currentDate、$rename、$unset、$bit,加上 $push、$pull、$addToSet、$pop 这些数组操作。

arrayFilters 我是单独挑出来测的。订单明细、库存条目、多层配置,改数组里指定的某一条是日常写法,兼容层最容易在这种地方露馅。

await orders.updateOne(
  { orderNo: &#x27;SO-20260723&#x27; },
  { $set: { &#x27;items.$[item].status&#x27;: &#x27;已发货&#x27; } },
  { arrayFilters: [{ &#x27;item.sku&#x27;: &#x27;SKU-1001&#x27; }] }
);

结果是通过的:只有 SKU-1001 那条明细的状态变了,同一数组里的其他明细原样没动。upsert、$setOnInsert、replaceOne、updateMany、deleteMany 一并过了。bulkWrite 的有序和无序两种模式分别跑,写入条数和最终文档内容都和预期一致。

TTL 确实删掉了过期文档

索引测了普通、复合、唯一、稀疏、部分、TTL、文本、通配符和哈希。唯一索引撞到重复值时,驱动收到 11000,和原生一致。

TTL 这一项我没停在”索引建出来了”。元数据建得出来,不代表后台任务真的在跑。所以写了一条已经过期的文档,等后台任务执行,再去查剩余数量,结果是 0。

await sessions.createIndex(
  { expireAt: 1 },
  { expireAfterSeconds: 0 }
);

collMod 改 TTL 过期时间也测了,命令会返回旧值和新值。英文文本索引用 $text 加 $search 查关键词,没问题。

聚合跑到了关联、递归和窗口计算

基础管道这一层没什么悬念:$match、$project、$group、$sort、$facet、$bucket、$bucketAuto、$sortByCount、$sample。

真正想看的是重的那几个。跨集合的 $lookup、合并结果集的 $unionWith、递归查询的 $graphLookup,各写了单独用例。$setWindowFields 的排名和窗口计算也过了。

const result = await orders.aggregate([
  { $match: { status: &#x27;已完成&#x27; } },
  { $group: {      _id: &#x27;$customerId&#x27;,      totalAmount: { $sum: &#x27;$amount&#x27; },      orderCount: { $sum: 1 }
  } },
  { $sort: { totalAmount: -1 } },
  { $limit: 20 }
]).toArray();

$out 把聚合结果写进集合,一次通过。$merge 一开始报错,按 MongoDB 对 on 字段唯一索引的要求补上索引之后完成了合并。这个行为和原生也是一样的。

JSON Schema 拦得住不合规文档

测试环境开了 documentdb.enableSchemaValidation=on。建集合时定义 $jsonSchema,要求 name 必填且是字符串,age 是非负整数。

await db.createCollection(&#x27;validated_users&#x27;, {  validator: {    $jsonSchema: {      bsonType: &#x27;object&#x27;,      required: [&#x27;name&#x27;],      properties: {        name: { bsonType: &#x27;string&#x27; },        age: { bsonType: &#x27;int&#x27;, minimum: 0 }
      }
    }
  }
});

合规文档正常写入。缺 name、name 类型不对、age 小于 0,数据库都返回 121 Document failed validation。也就是说,一部分基础数据规则可以压到集合上,不用全堆在应用层。

事务和 GridFS

事务从 startSession 开始,提交和回滚分别测。提交后查得到,回滚后查不到,多集合事务用同样的方式核对。

还有一条用例我比较在意:起一个活动事务,再用 killSessions 把会话干掉。会话结束之后,那个事务的未提交写入没有留在集合里。这条要是不通过,应用异常断连的场景会很难收拾。

GridFS 就是走完一圈:上传文件、下载、比对内容、删除。

const bucket = new GridFSBucket(db, { bucketName: &#x27;attachments&#x27; });const uploadId = new ObjectId();await new Promise((resolve, reject) => {  const stream = bucket.openUploadStreamWithId(uploadId, &#x27;report.pdf&#x27;);
  stream.once(&#x27;finish&#x27;, resolve);
  stream.once(&#x27;error&#x27;, reject);
  stream.end(Buffer.from(&#x27;report content&#x27;));
});

这轮测下来,我的判断

兼容度比我预期的高。

19 加 38 个场景,从 BSON 类型、CRUD、索引,一路到聚合、JSON Schema、事务和 GridFS,官方驱动全程没换写法,也没有为了绕开哪个不支持的特性去改代码。$graphLookup、$setWindowFields、arrayFilters、TTL 后台回收、killSessions 之后的事务清理,这几条是我事先觉得最容易出问题的,结果都过了。$merge 那次报错也不算兼容问题,补上 on 字段的唯一索引就通过,要求和原生 MongoDB 一致。

对已有项目来说,改造入口很清楚:换掉测试环境的连接串,把集合初始化、核心读写、索引和聚合管道跑一遍回归,跑完就知道数据层要动多少。以这次的结果看,用 Node.js 驱动的应用大概率不用动多少代码。


这轮的定位是功能验证,结论是能用,而且用得很顺。接下来我打算拿真实的集合结构和数据量再跑一轮,重点看性能、复制和高可用。功能这一层已经看清楚了,剩下的是把量压上去。各位朋友觉得Kingbase的这个版本如何?

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/23825935/viewspace-3176627/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
11年数据库行业经验,Oracle ACE、PG ACE、OCM、IBM Certified DBA、MySQL OCP、PolarDB技术专家、KCP、PCTP、PCSD、达梦师资认证、PolarDB开源社区技术顾问、ITPUB认证专家、某高校外聘教师

注册时间:2019-05-05

  • 博文量
    295
  • 访问量
    300791