Go GJSON 怎么一次读取多个不同路径的值
来源:17golang原创
时间:2026-10-13 15:59:34 311浏览 收藏
Go GJSON 需要读取多个不同路径时,最稳妥的做法是先用 gjson.Parse(或 ParseBytes)得到一个 Result,再通过 Result.Get 读取各个路径。这样同一份输入只建立一次解析结果;如果多个字段来自数组中的同类对象,再用 # 投影和多路径语法组合精简对象。
官方地址:https://github.com/tidwall/gjson
- 多个独立路径:解析一次,连续调用
root.Get(path)。 - 同一数组的多个字段:用
items.#.field或多路径对象收敛输出。 - 缺失字段先看
Exists(),不要用空字符串代替业务判断。
解析一次,再读取多个独立路径
例如订单接口同时返回客户编号、订单金额和会员标记。直接对原字符串调用多次 gjson.Get 也能得到结果,但代码会把“输入文本”重复传入。把输入先交给 gjson.Parse,后续路径就集中在一个根结果上,便于统一处理缺失字段。
package main
import (
"fmt"
"github.com/tidwall/gjson"
)
func main() {
payload := `{"customer":{"id":"C-17"},"order":{"total":128.5},"flags":{"vip":true}}`
// 只解析一次,后面的 Get 都从同一个根结果继续查找。
root := gjson.Parse(payload)
customerID := root.Get("customer.id")
total := root.Get("order.total")
vip := root.Get("flags.vip")
// 先判断存在性,再按 JSON 实际类型读取,避免空字符串掩盖缺失字段。
fmt.Println(customerID.Exists(), customerID.String())
fmt.Println(total.Exists(), total.Float())
fmt.Println(vip.Exists(), vip.Bool())
}

这里的“多个”是多个独立路径,不是一个叫作 GetMany 的标准 API。Result.Get 返回的仍是 gjson.Result:字符串使用 String(),数字使用 Int() 或 Float(),布尔值使用 Bool()。如果输入已经是字节切片,换成 gjson.ParseBytes(data) 即可。
数组字段用 # 做批量投影
当多个值来自数组中的同名字段,不必手写 items.0.id、items.1.id。路径中的 # 表示数组长度或遍历位置,items.#.id 会得到所有元素的 id,结果仍然是 JSON 数组。
package main
import (
"fmt"
"github.com/tidwall/gjson"
)
func main() {
payload := `{"items":[{"id":101,"sku":"A-17","qty":2},{"id":102,"sku":"B-03","qty":1}]}`
// # 遍历 items,并把每个对象的 id 投影成结果数组。
ids := gjson.Get(payload, "items.#.id")
for _, item := range ids.Array() {
// 数字字段优先用 Int(),不要先转 String() 再解析。
fmt.Println(item.Int())
}
// 同一输入还可以读取另一条独立路径,二者互不改变。
quantities := gjson.Get(payload, "items.#.qty")
fmt.Println(quantities.Raw)
}
如果要筛选数组中的多个匹配项,使用 #(条件)#;末尾第二个 # 很关键,因为没有它时通常只取第一个命中对象。筛选和投影是两个动作,先确定是否要“找哪些元素”,再决定要“留下哪些字段”。
同一对象的多个字段用多路径组装
如果调用方希望得到一个只包含指定字段的新对象数组,可以把字段映射写进多路径语法。例如 users.#.{"id":id,"name":name} 会遍历用户数组,并为每项创建只含 id 和 name 的对象。别名也可以不同,适合给下游接口生成稳定的展示结构。
package main
import (
"fmt"
"github.com/tidwall/gjson"
)
func main() {
payload := `{"users":[{"id":7,"name":"Lin","role":"editor"},{"id":8,"name":"Qiao","role":"viewer"}]}`
// 多路径只选择 id 和 name,role 等无关字段不会进入结果。
compact := gjson.Get(payload, `users.#.{"id":id,"display_name":name}`)
if compact.Type != gjson.JSON {
// 类型不符合预期时及时停止向下游传递错误形态。
panic("expected JSON array")
}
fmt.Println(compact.Raw)
}

筛选也能接在投影前面,例如 users.#(role=="editor")#. {"id":id}(实际路径中不要在点后插入空格)可以先收集所有编辑者,再只保留编号。实际项目中建议把这类路径集中成常量,避免散落在业务代码里难以修改。
缺失字段、空值与强类型转换
| 场景 | 建议写法 | 原因 |
|---|---|---|
| 判断字段是否存在 | result.Exists() | 区别于存在但值为空 |
| 保留 JSON 形态 | result.Raw | 适合直接转发数组或对象 |
| 读取整数 | result.Int() | 避免先转字符串 |
| 需要复杂校验 | 解码到结构体 | GJSON 不替代领域校验 |
最后可以按这个边界选择方案:不同位置的少量字段,使用“解析一次 + 多次 Get”;数组同名字段,使用 #.字段;数组中每项要保留多个字段,使用多路径对象;如果后续需要必填校验、默认值和业务约束,再把精简后的 JSON 或完整输入交给结构体解码。
相关问题
多次调用 Result.Get 会重新解析整段 JSON 吗?
它会在根结果的原始 JSON 上继续查找,但代码层面复用了同一个解析结果。若路径数量很多,仍应把路径和取值逻辑集中管理,避免业务判断散落。
为什么读取不存在的路径后 String() 是空字符串?
空字符串可能来自缺失字段,也可能来自真实的空值。先调用 Exists(),必要时再检查 Type,不要只用 String() 的返回值判断。
多路径结果能直接当作 Go 结构体吗?
不能直接当作强类型结构体。多路径首先返回 gjson.Result 和 JSON 原文;需要强类型字段、必填规则或复杂校验时,仍要使用标准 JSON 解码或项目自己的转换层。
-
860 收藏
-
843 收藏
-
826 收藏
-
809 收藏
-
792 收藏
-
321 收藏
-
450 收藏
-
413 收藏
-
351 收藏
-
293 收藏
-
334 收藏
-
246 收藏
-
174 收藏
-
119 收藏
-
435 收藏
-
405 收藏
-
111 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习