Slonik:如何安全使用JSONB_PATH_MATCH查询JSONB对象?
问题:Slonik中安全查询JSONB路径匹配的简便实现
我的PostgreSQL表中有一个存储聚合JSONB对象的列,数据示例如下:
id | agg_jsonb_objects ------+--------------------------------------------------------- 1 | {"recordA": {"fieldA": "A"}, "recordB": {"fieldA": "B"}}
需求是查询所有包含值为“B”的“fieldA”的行,在终端中用以下SQL可以实现:
SELECT id FROM your_table WHERE JSONB_PATH_MATCH(agg_jsonb_objects, 'exists($ ?(@.**.fieldA == "B"))')
但用Slonik构建服务端安全查询时遇到问题:
- 使用
raw()可以运行,但存在SQL注入风险; - 直接传入参数会报错“could not determine data type of parameter $1”;
- 手动处理不同类型值的格式(如字符串加引号、数值不用加)可以运行,但过于繁琐,想找更简便的实现方式。
解决方案
方法1:参数化JSON路径查询(适配复杂路径)
利用PostgreSQL的jsonb_build_object将参数封装为JSONB对象,在路径表达式中通过命名参数引用,Slonik可安全传递参数且无需手动处理格式:
const targetValue = 'B'; const query = sql` SELECT id FROM your_table WHERE jsonb_path_match( agg_jsonb_objects, 'exists($ ?(@.**.fieldA == $val))', jsonb_build_object('val', ${targetValue}) ) `;
原理:jsonb_build_object会根据传入参数的类型自动生成对应JSON类型的值,路径表达式中的$val会引用这个JSONB对象中的键值,PostgreSQL能自动识别参数类型,避免手动拼接引号或处理类型差异。
方法2:展开JSONB后过滤(直观易维护)
如果JSONB结构是顶层键值对的聚合,可通过jsonb_each展开对象后直接过滤,Slonik参数处理更简单:
const targetValue = 'B'; const query = sql` SELECT DISTINCT t.id FROM your_table t JOIN jsonb_each(t.agg_jsonb_objects) j(key, value) ON j.value->>'fieldA' = ${targetValue} `;
原理:jsonb_each将顶层JSONB对象拆分为键值行,通过->>提取fieldA的文本值后直接和参数比较,完全规避JSON路径表达式的参数类型问题,代码可读性更高。
内容的提问来源于stack exchange,提问作者fakechek
相关产品推荐
相关产品推荐

