You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何可靠排序jsonb键?Python复现PostgreSQL加密场景遇阻

解决PostgreSQL jsonb键排序的Python复现方案

我刚好碰到过类似的问题,PostgreSQL的jsonb类型在转为文本(比如用::text)时,会递归地对所有嵌套对象的键进行排序,排序规则依赖数据库的默认collation(通常是C collation,即按字符的Unicode码点升序排列),数组元素的顺序则保持不变。要在Python里复现这个逻辑,我们可以写一个递归函数来处理JSON结构的键排序,再配合有序字典或排序后的字典来模拟。

核心逻辑说明

PostgreSQL的jsonb转文本的键排序规则:

  • 所有层级的JSON对象(包括嵌套的)都会对键进行排序
  • 排序依据是数据库的collation规则(默认C collation对应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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 02:28:45