前言
postgres的jsonb字段,是支持查询的,并且查询速度不俗,因为是树形结构。我们知道查询某一个字段的值是这样写:
- 查询username=kling的记录
where raw::jsonb ->> 'username' = 'kling'
那么,如何支持jsonb字段未知深度的子字段查询呢?比如:
- 查询班主任叫张三的记录
where (raw::jsonb ->> class)::jsonb ->> 'master_name' = '张三'
甚至于深度很长。
实现:
// 生成动态的jsonb查询条件,不支持对子字段为数组的数据进行查询
// 条件:
// chain json字段链长度最少为2,其中第一个参数为主表字段,后面的参数为子字段
// condition 必须为数据库支持的条件判断符号
// value 为数据库支持的正常值
// 示例:
// chain = []string{"raw", "zonst_vx", "game_id}
// condition = "="
// value = "5"
// 输出: ((raw)::jsonb ->>'zonst_vx')::jsonb ->>'game_id'='5'
func JSONBWhere(chain []string, condition string, value string) (string) {
return fmt.Sprintf("%s%s'%s'", countJSONB(chain), condition, value)
}
func point(field string, subfield string) string {
return fmt.Sprintf("(%s)::jsonb ->>'%s'", field, subfield)
}
func countJSONB(chain []string) string {
if len(chain) == 2 {
return point(chain[0], chain[1])
}
sub := chain[:len(chain)-1]
last := chain[len(chain)-1]
return point(countJSONB(sub), last)
}
示例:
func TestJSONWhere(t *testing.T) {
fmt.Println(JSONBWhere([]string{
"raw", "zonst_vx", "game_id"}, "=", "5"))
}
输出:
((raw)::jsonb ->>'zonst_vx')::jsonb ->>'game_id'='5'
实际使用
- gorm
type JSONQuery struct{
Enable bool `json:"enable"`
FieldName string `json:"field_name"`
Condition string `json:"condition"`
Value string `json:"value"`
}
var jsonQuery = JSONQuery{
Enable: true,
FieldName: "raw.class.master_name",
Condition: "=",
Value: "张三",
}
if jsonQuery.Enable {
db.Where(JSONBWhere(
strings.Split(jsonQuery.FieldName, "."),
jsonQuery.Condition,
jsonQuery.Value,
))
}