登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  数据库 >  MySQL

MySQL JSON_LENGTH 怎样分别统计对象成员和数组元素

来源:17golang原创

时间:2026-11-13 20:48:31 234浏览 收藏

MySQL 的 JSON_LENGTH() 不是计算 JSON 文本的字符数,而是计算一个 JSON 值的直接成员数量:数组返回元素数,对象返回成员数,标量返回 1。如果传入路径,就先定位路径对应的值,再按同一规则计数;路径不存在时返回 NULL。

官方地址:https://dev.mysql.com/doc/refman/8.4/en/json-attribute-functions.html

因此,判断结果时先问“当前路径拿到的是什么类型”,再解释数字含义。嵌套对象和数组不会递归累加,统计的是当前值的第一层。

对象、数组和标量的长度规则

可以把 JSON_LENGTH() 看成一个直接层级计数器:

JSON 值返回含义示例结果
数组直接元素数量[10,20,{"a":3}] 返回 3
对象直接键值成员数量{"a":1,"b":{"c":30}} 返回 2
标量标量本身算一个值true 返回 1
嵌套对象或数组只占一个直接成员位置不会把内部成员继续相加
MySQL JSON_LENGTH 按对象数组标量类型计数的静态说明图
图1:操作示意图。不同 JSON 类型进入 JSON_LENGTH 后分别采用对象成员、数组元素和标量三种计数规则;这是静态说明图,不是运行截图。

用最小 SQL 统计顶层对象和数组

先用字面量理解“直接层级”:

-- 分别观察数组、对象和标量;每个表达式都只统计当前值
SELECT
  JSON_LENGTH('[10, 20, {"a": 3}]') AS array_count,
  JSON_LENGTH('{"a": 1, "b": {"c": 30}}') AS object_count,
  JSON_LENGTH('true') AS scalar_count;

预期含义是 3、2、1。数组中的对象只算数组的第三个元素;对象中的嵌套对象只算对象的第二个成员。若业务要求“所有嵌套节点总数”,JSON_LENGTH() 本身不是递归遍历器,需要改用明确的遍历方案。

在表字段上使用时,先给查询起一个清晰的别名,避免把 JSON 长度误当成字符串长度:

-- 读取订单扩展字段的顶层成员数;这里假设 extra_info 是 JSON 列
SELECT
  order_id,
  JSON_LENGTH(extra_info) AS top_level_member_count
FROM order_demo
WHERE order_id = 1001;

用 path 参数统计嵌套数组或对象

第二个参数是 JSON path。它不会改变计数规则,只决定计数对象从整个文档切换到某个子值:

-- 先取 payload.items 数组,再统计其中的直接元素
SELECT JSON_LENGTH(
  '{"payload":{"items":[{"id":1},{"id":2}],"meta":{"source":"api"}}}',
  '$.payload.items'
) AS item_count;

-- 统计 payload.meta 对象的直接成员;嵌套路径不存在时结果为 NULL
SELECT JSON_LENGTH(
  '{"payload":{"items":[1,2],"meta":{"source":"api"}}}',
  '$.payload.meta'
) AS meta_member_count;

第一个查询的目标值是数组,所以返回数组元素数;第二个目标值是对象,所以返回对象成员数。路径表达式必须合法,路径找不到值时返回 NULL,不能把它当作空数组的 0。

MySQL JSON_LENGTH 使用路径定位嵌套值并返回边界结果的静态说明图
图2:结果示意图。路径先把文档定位到目标子值,再沿用同一套计数规则;NULL、0 和 1 分别可能来自不同边界,不能混为一谈。

NULL、空容器和无路径结果要分开

实际排查中最容易混淆的是以下几种情况:

  • 空数组 [] 的长度是 0。
  • 空对象 {} 的长度是 0。
  • 标量(例如字符串、数字、布尔值)长度是 1。
  • SQL 参数为 NULL,或 path 没有定位到值时,返回 NULL。
  • JSON 文档或 path 表达式非法时会报错,而不是返回一个普通计数。
-- 用 IFNULL 只在业务明确允许时把“未找到”映射成 0
SELECT
  JSON_LENGTH('{"items":[]}', '$.items') AS empty_array_count,
  JSON_LENGTH('{"meta":{}}', '$.meta') AS empty_object_count,
  JSON_LENGTH('{"items":[1]}', '$.missing') AS missing_path_count,
  IFNULL(JSON_LENGTH('{"items":[1]}', '$.missing'), 0) AS missing_as_zero;

最后一列只是展示业务映射,不代表“路径不存在”天然等于“空集合”。如果后续逻辑需要区分“字段缺失”和“字段存在但为空”,请保留原始的 NULL,不要过早使用 IFNULL。

用 JSON_TYPE 确认数字到底代表什么

当 JSON 来自用户输入或旧数据时,建议把类型一起读出来。这样看到 1 时,能知道它是一个标量,还是包含一个元素的数组,还是只有一个成员的对象。

-- 同时读取目标值类型和长度,避免只看数字作错误推断
SET @doc = '{"value": [10], "meta": {"source": "api"}}';

SELECT
  JSON_TYPE(JSON_EXTRACT(@doc, '$.value')) AS value_type,
  JSON_LENGTH(@doc, '$.value') AS value_length,
  JSON_TYPE(JSON_EXTRACT(@doc, '$.meta')) AS meta_type,
  JSON_LENGTH(@doc, '$.meta') AS meta_length;

JSON_TYPE() 用来解释类型,JSON_LENGTH() 用来解释当前类型的直接数量。两者配合比单独输出长度更适合日志、数据清洗和接口字段排查。

常见误区与选择建议

现象正确解释处理建议
结果是 1可能是标量,也可能是一个元素的数组或一个成员的对象同时读取 JSON_TYPE
嵌套数据没有全部累加函数只统计当前值的直接层级明确是否需要递归遍历
无路径返回 NULL路径没有定位到值,不等于空容器按业务决定是否映射为 0
字符串很长但长度为 1JSON 字符串是一个标量不要用 JSON_LENGTH 计算字符数

如果目标是统计对象字段数或数组元素数,直接使用 JSON_LENGTH(doc, path);如果目标是判断类型,追加 JSON_TYPE;如果目标是统计所有深层节点,先设计遍历和去重规则,不能把当前函数当作递归统计器。

JSON_LENGTH 能统计字符串字符数吗?

不能。字符串属于标量,按 JSON_LENGTH 的规则返回 1。字符数应使用适合字符串的函数,并先确认取出的值是否已经去掉 JSON 包装。

空数组和路径不存在为什么不能都当成 0?

空数组表示目标值存在但没有元素;路径不存在表示没有找到目标值。两者语义不同,只有业务明确不需要区分时才可以统一映射。

怎样统计嵌套数组的元素总数?

JSON_LENGTH 只统计指定数组这一层。如果数组元素内部还包含数组,需要先定义遍历层级,再选择 JSON_TABLE 或应用层递归等方案。

记住一句话:JSON_LENGTH 统计的是“当前 JSON 值的直接数量”,不是文本长度,也不是整棵树的节点总数。先用 JSON_TYPE 确认类型,再用 path 把计数范围缩小,最后决定是否保留 NULL 的语义。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>