PostgreSQL使用json_strip_nulls后,如何去除JSON/JSONB空对象?
嘿,这个场景我太熟了!json_strip_nulls确实只能帮你去掉null值,但空对象(比如location: {})和数组里的空元素(比如events里的{})得额外处理,给你两个实用的方案,看你需求选:
方案一:递归自定义函数(通用嵌套场景)
如果你的JSON结构有多层嵌套(比如对象里套对象、数组里套对象),写个递归函数是最省心的,能一次性清理所有空对象,不管层级多深:
CREATE OR REPLACE FUNCTION jsonb_clean_empty_objects(jsonb_data jsonb) RETURNS jsonb AS $$ BEGIN -- 第一步:先去掉所有null值 jsonb_data := jsonb_strip_nulls(jsonb_data); -- 递归处理每个键值对: jsonb_data := jsonb_object_agg( key, CASE -- 空对象直接标记为null,后续会被strip掉 WHEN value = '{}'::jsonb THEN NULL -- 嵌套对象递归清理 WHEN jsonb_typeof(value) = 'object' THEN jsonb_clean_empty_objects(value) -- 数组遍历元素,去掉空对象,递归处理后保留非空元素 WHEN jsonb_typeof(value) = 'array' THEN ( SELECT jsonb_agg(elem) FROM jsonb_array_elements(value) elem WHERE elem != '{}'::jsonb AND jsonb_clean_empty_objects(elem) IS NOT NULL ) -- 其他类型直接保留 ELSE value END ) FROM jsonb_each(jsonb_data); -- 最后再清理一次,去掉被标记为null的属性 RETURN jsonb_strip_nulls(jsonb_data); END; $$ LANGUAGE plpgsql IMMUTABLE;
使用的时候直接把你的JSON字段传进去就行:
-- 假设你的数据存在test表的data字段中 SELECT jsonb_clean_empty_objects(data) AS cleaned_json FROM test;
处理后的结果会是:
{"id": 1, "organization_id": 1, "pairing_id": 1, "device": {"tracking_id": 1}, "events": []}
如果连空数组也想一并去掉,只需要修改数组处理的逻辑,当聚合后的数组为空时返回null,最后jsonb_strip_nulls就会把它移除。
方案二:JSON路径表达式(轻量简单场景)
如果你的JSON结构比较简单(只有顶层空对象和一维数组),用PostgreSQL 12+支持的JSON路径表达式更直接,不用写函数:
SELECT jsonb_strip_nulls( -- 移除顶层的空对象location jsonb_set( jsonb_strip_nulls(data), '{events}', -- 过滤events数组里的空对象 (SELECT jsonb_agg(elem) FROM jsonb_array_elements(data->'events') elem WHERE elem != '{}'::jsonb), true ) - 'location' ) AS cleaned_json FROM test;
这个方法的逻辑是:先清理null值,然后更新events数组过滤掉空对象,再移除顶层的空location属性,最后再清理一次确保没有遗漏的null。
两种方案都能解决你的问题,要是嵌套层级多就选递归函数,结构简单就用JSON路径更快捷~
内容的提问来源于stack exchange,提问作者user1079877
相关产品推荐
相关产品推荐

