GORM查询PostgreSQL嵌套JSONB数据报语法错误如何解决
GORM操作PostgreSQL JSONB嵌套查询的参数转义问题解决
问题场景
products表包含JSONB类型的info列,存储数据示例如下:
{ "ID": 1, "NAME": "Product A", "INFO": { "DESCRIPTION": "lorem ipsum", "BUYERS": [ { "ID": 1, "NAME": "John Doe" }, { "ID": 2, "NAME": "Jane Doe" } ] } }
- 需求:匹配
BUYERS数组内任意买家姓名,查询对应的商品记录 - 可正常运行的原生PostgreSQL语句:
SELECT * FROM products WHERE info -> 'buyers' @> '[{"name": "Jane Doe"}]'
- 失效的GORM写法:
result = db.Where("info-> 'buyers' @> '[{\"name\": ?}]'", request.body.name).Find(&products)
- 执行报错信息:
SELECT * FROM "products" WHERE info -> 'buyers' @> '[{"name": 'Jane Doe'}]' ERROR: invalid input syntax for type json (SQLSTATE 22P02)
- 错误根因:GORM为字符串类型参数自动包裹SQL语法要求的单引号,当占位符写在JSON字面量内部时,单引号会直接插入JSON结构中,破坏JSON规范要求的双引号字符串格式,最终导致JSONB解析失败。
可行解决方案
方案1:预序列化JSON查询片段(推荐)
不要把占位符写在JSON字符串内部,提前将查询条件序列化为标准合法的JSON字符串,将整个JSON串作为参数传入占位符:
import "encoding/json" // 构造匹配规则,序列化为标准JSON格式 matchCondition, err := json.Marshal([]map[string]string{ {"name": request.Body.Name}, }) if err != nil { // 自行处理序列化异常 } // 整个JSON片段作为参数传递,GORM只会在整个JSON串外层包裹SQL单引号 result = db.Where("info -> 'buyers' @> ?", matchCondition).Find(&products)
这种写法生成的SQL完全符合JSONB语法要求,JSON内部的键、值都会保留标准双引号格式,不会出现引号嵌套错误。
方案2:使用PostgreSQL内置JSONB构造函数
如果不想额外做JSON序列化,可以直接调用PostgreSQL内置函数动态构造JSONB查询条件,参数以普通字符串形式传入,不会出现引号冲突:
result = db.Where( `info -> 'buyers' @> jsonb_build_array(jsonb_build_object('name', ?))`, request.Body.Name, ).Find(&products)
注意事项
如果存储的JSONB字段键名为大写(比如示例中的BUYERS/NAME),SQL语句中访问键的路径要和实际存储的键名完全一致,否则会出现匹配不到数据的问题。
内容的提问来源于stack exchange,提问作者mathias yeremia
相关产品推荐
相关产品推荐

