如何可靠排序jsonb键?Python复现PostgreSQL加密场景遇阻
解决PostgreSQL jsonb键排序的Python复现方案
我刚好碰到过类似的问题,PostgreSQL的jsonb类型在转为文本(比如用::text)时,会递归地对所有嵌套对象的键进行排序,排序规则依赖数据库的默认collation(通常是C collation,即按字符的Unicode码点升序排列),数组元素的顺序则保持不变。要在Python里复现这个逻辑,我们可以写一个递归函数来处理JSON结构的键排序,再配合有序字典或排序后的字典来模拟。
核心逻辑说明
PostgreSQL的jsonb转文本的键排序规则:
- 所有层级的JSON对象(包括嵌套的)都会对键进行排序
- 排序依据是数据库的collation规则(默认
Ccollation对应Unicode码点升序) - 数组元素的顺序完全保留,不会被排序
- 排序是深度优先的,每个嵌套对象独立处理键的顺序
Python实现代码
下面是一个可直接复用的递归排序函数,能完美模拟PostgreSQL的键排序逻辑:
import json from collections import OrderedDict def sort_json_keys(obj, collation_key=str): """ 递归排序JSON对象的所有键,模拟PostgreSQL jsonb转文本时的排序行为 :param obj: 输入的JSON结构(dict、list或基本数据类型) :param collation_key: 排序用的键函数,默认str对应PostgreSQL的C collation :return: 键排序后的JSON结构,嵌套对象的键均已排序 """ if isinstance(obj, dict): # 对当前字典的键排序,再递归处理每个值 sorted_items = sorted(obj.items(), key=lambda x: collation_key(x[0])) return OrderedDict((k, sort_json_keys(v, collation_key)) for k, v in sorted_items) elif isinstance(obj, list): # 数组元素保持原顺序,递归处理每个元素 return [sort_json_keys(item, collation_key) for item in obj] else: # 基本数据类型直接返回 return obj # 示例使用 if __name__ == "__main__": # 原始嵌套JSON对象 original_json = { "z": 1, "a": {"b": 2, "a": 3}, "list": [{"y": 4, "x": 5}, 6] } # 生成键排序后的结构 sorted_json = sort_json_keys(original_json) # 转成和PostgreSQL输出一致的无空格JSON字符串 sorted_json_str = json.dumps(sorted_json, separators=(',', ':')) print("排序后的JSON字符串:") print(sorted_json_str) # 输出和PostgreSQL执行SELECT '{"z":1,"a":{"b":2,"a":3},"list":[{"y":4,"x":5},6]}'::jsonb::text;结果一致 # PostgreSQL输出:{"a":{"a":3,"b":2},"list":[{"x":5,"y":4},6],"z":1} # 模拟加密步骤(替换成你实际的加密算法) import hashlib encrypted_result = hashlib.sha256(sorted_json_str.encode('utf-8')).hexdigest() print("\n加密后的结果:") print(encrypted_result)
适配非默认Collation的情况
如果你的PostgreSQL数据库使用的是其他collation(比如en_US.UTF-8),需要调整排序的键函数来匹配:
import locale # 设置对应数据库的locale locale.setlocale(locale.LC_COLLATE, 'en_US.UTF-8') def db_collation_key(s): # 用locale.strxfrm模拟数据库的排序规则 return locale.strxfrm(s) # 使用自定义排序键 sorted_json = sort_json_keys(original_json, db_collation_key)
注意:不同环境下的locale实现可能和PostgreSQL有细微差异,建议用实际的数据库输出对比验证,调整排序逻辑。
内容的提问来源于stack exchange,提问作者Erik
相关产品推荐
相关产品推荐

