金仓支持统一sql与mongo语法共存查询混合schema数据。jsonb字段可直接用jsonb_path_query()等函数,text字段需cast;混合类型需用jsonb_typeof()判别并容错强转;gin索引按路径预定义,高频更新字段建议物化视图;权限控制需通过生成列实现字段级授权。

混合Schema数据在金仓里怎么查?用统一SQL还是Mongo语法?
金仓数据库不强制你二选一。它支持两种方式共存:既可以用 find()、aggregate() 这类 MongoDB 原生命令直连查询,也能用标准 SQL 对同一张表里的 JSON 字段做深度解析。关键在于字段类型定义——如果你建表时把字段声明为 JSONB,那 jsonb_path_query()、jsonb_set() 就能直接用;如果只是普通 TEXT,就得先 CAST 再处理,性能会打折扣。
常见错误是误以为“兼容 MongoDB”=“只能用 MongoDB 语法”。实际上线后发现聚合管道写多了,跨集合关联却没法用 JOIN,最后又得补 SQL 视图。建议初期就明确:高频嵌套查询走 aggregate(),需要和关系字段(如 user_id、create_time)联合过滤或排序的,优先建 JSONB 字段 + 补充生成列索引。
同一个字段存了 string/number/null,查询结果总不准怎么办?
这是 MongoDB 混合 Schema 最典型的坑,在金仓里同样存在。比如 age 字段有的文档存的是 25,有的存的是 "25",还有的干脆是 null。直接 WHERE age > 20 会漏掉字符串型数据,甚至报类型转换错误。
- 用
jsonb_typeof()先判类型:WHERE jsonb_typeof(data->'age') = 'number' - 用
jsonb_path_exists()确保字段存在:AND jsonb_path_exists(data, '$.age') - 强转时加容错:
(data->>'age')::numeric会失败,但NULLIF((data->>'age'), '')::numeric能绕过空字符串
注意:这些函数只对 JSONB 类型有效。如果原始数据是 BSON 格式直写进来的,金仓会自动转成 OSON,但类型推断逻辑和纯 JSONB 略有差异,建议迁移前用 jsonb_pretty() 抽样检查结构一致性。
索引怎么建才不浪费资源又覆盖所有查询路径?
金仓支持在 JSONB 字段上建 GIN 索引,但和 MongoDB 的嵌套索引(如 {"user.info.age": 1})不是一一对应的关系。它更依赖路径表达式预定义。
- 单字段高频查:建
jsonb_path_ops索引,例如CREATE INDEX idx_user_age ON orders USING GIN ((data->'user'->'info'->'age')); - 多路径组合查:用
jsonb_path_query_array()提前展开再建普通 B-tree 索引,避免每次查询都解析 - 全文检索场景:必须配合
to_tsvector('chinese', data->>'content')+ GIN,不能指望$text自动生效
容易被忽略的是:GIN 索引体积大、写入慢。如果某 JSONB 字段更新频繁(比如物流轨迹实时追加),索引反而会拖累整体吞吐。这时宁可牺牲部分查询速度,改用物化视图定期刷新。
权限怎么管?字段级控制能落到 JSON 内部吗?
能,但不是靠 MongoDB 那套 db.collection.update() 权限粒度。金仓的权限体系基于 SQL 标准,所以字段级控制只作用于表结构层——你得先把 JSON 里的关键字段抽出来作为生成列(generated column),再对这个列单独授权。
例如想限制运维人员看不到 data->'payment'->'card_no',就得:
- 建表时加
card_no_hidden TEXT GENERATED ALWAYS AS (data->'payment'->>'card_no') STORED - 然后
REVOKE SELECT ON COLUMN card_no_hidden FROM ops_role
直接对 data 字段设权限没用,JSONB 是原子存储单元。另外,行级策略(RLS)可以结合 current_user 和 jsonb_path_exists() 动态过滤,但别在聚合管道里用——aggregate() 不走 RLS 规则。











