最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用Python與PostgreSQL的JSON數(shù)據(jù)進(jìn)行交互

 更新時(shí)間:2026年02月07日 09:51:00   作者:數(shù)據(jù)知道  
PostgreSQL自9.2版本起原生支持JSON數(shù)據(jù)類型,并在后續(xù)版本中不斷增強(qiáng)其功能,現(xiàn)已提供JSON和JSONB兩種類型、豐富的操作符、索引支持及函數(shù)體系,本文將系統(tǒng)講解如何在Python中高效、安全、可維護(hù)地與PostgreSQL的JSON數(shù)據(jù)交互,需要的朋友可以參考下

PostgreSQL 自 9.2 版本起原生支持 JSON 數(shù)據(jù)類型,并在后續(xù)版本中不斷增強(qiáng)其功能,現(xiàn)已提供 JSONJSONB 兩種類型、豐富的操作符、索引支持及函數(shù)體系。與此同時(shí),Python 作為數(shù)據(jù)處理的主流語(yǔ)言,與 PostgreSQL 的結(jié)合日益緊密。

本文將系統(tǒng)講解如何在 Python 中高效、安全、可維護(hù)地與 PostgreSQL 的 JSON 數(shù)據(jù)交互,涵蓋:

  • JSON 與 JSONB 的區(qū)別與選型
  • 使用 psycopg2asyncpg 等主流驅(qū)動(dòng)
  • 自動(dòng)序列化/反序列化 Python 字典與 JSON
  • 復(fù)雜查詢:路徑提取、條件過(guò)濾、更新操作
  • 性能優(yōu)化與索引策略
  • 實(shí)戰(zhàn)案例:配置存儲(chǔ)、日志分析、動(dòng)態(tài)表單等

一、PostgreSQL 中的 JSON 類型基礎(chǔ)

參考

  • PostgreSQL JSON 函數(shù)文檔:https://www.postgresql.org/docs/current/functions-json.html
  • psycopg2 JSON 支持:https://www.psycopg.org/docs/extras.html#json-adaptation
  • asyncpg 類型映射:https://magicstack.github.io/asyncpg/current/usage.html#type-conversion

1.1 JSON vs JSONB:關(guān)鍵區(qū)別

特性JSONJSONB
存儲(chǔ)格式文本(保留原始格式)二進(jìn)制(解析后存儲(chǔ))
是否去重否(保留重復(fù)鍵)是(僅保留最后一個(gè)鍵值)
是否保留順序否(對(duì)象鍵無(wú)序)
索引支持不支持(需表達(dá)式索引)支持 GIN、GiST 索引
查詢性能較慢(每次需解析)快(已解析為內(nèi)部結(jié)構(gòu))
存儲(chǔ)空間較大較?。o(wú)空白、無(wú)重復(fù))

推薦:除非必須保留原始 JSON 格式(如審計(jì)日志),否則一律使用 JSONB

1.2 常用操作符與函數(shù)

1、路徑提取

->:返回 JSON 對(duì)象(仍為 JSONB)

SELECT data->'user'->'name' FROM logs;

->>:返回文本(TEXT)

SELECT data->>'status' FROM orders;

2、條件查詢

檢查鍵是否存在:

SELECT * FROM events WHERE data ? 'error_code';

檢查嵌套路徑:

SELECT * FROM configs WHERE data @> '{"feature": {"enabled": true}}';

3、更新操作

設(shè)置字段(PostgreSQL 9.5+):

UPDATE users SET profile = jsonb_set(profile, '{settings,theme}', '"dark"');

二、Python 驅(qū)動(dòng)選擇與配置

2.1 主流驅(qū)動(dòng)對(duì)比

驅(qū)動(dòng)異步支持JSON 自動(dòng)轉(zhuǎn)換成熟度適用場(chǎng)景
psycopg2需手動(dòng)注冊(cè)適配器同步應(yīng)用、Django、Flask
psycopg2-binary同上快速原型、無(wú)需編譯
asyncpg自動(dòng)轉(zhuǎn)換 dict ↔ JSONB異步框架(FastAPI, aiohttp)
SQLAlchemy + psycopg2通過(guò) JSON / JSONB 類型自動(dòng)處理極高ORM 場(chǎng)景

2.2 PostgreSQL 的 JSONB 與 Python 的結(jié)合注意點(diǎn)

PostgreSQL 的 JSONB 與 Python 的結(jié)合,為處理半結(jié)構(gòu)化數(shù)據(jù)提供了強(qiáng)大而靈活的方案。通過(guò)合理選擇驅(qū)動(dòng)、配置自動(dòng)轉(zhuǎn)換、利用索引和操作符,可實(shí)現(xiàn):

  • 開發(fā)效率高:無(wú)需預(yù)定義 schema
  • 查詢能力強(qiáng):支持復(fù)雜嵌套查詢
  • 性能可優(yōu)化:GIN 索引、路徑索引保障效率

但也要謹(jǐn)記:

  • 不要濫用 JSON:結(jié)構(gòu)化數(shù)據(jù)仍應(yīng)使用關(guān)系模型
  • 保持查詢簡(jiǎn)單:避免過(guò)度嵌套導(dǎo)致維護(hù)困難
  • 監(jiān)控性能:定期分析執(zhí)行計(jì)劃

三、使用 psycopg2 處理 JSON

3.1 基礎(chǔ)連接與自動(dòng)轉(zhuǎn)換

默認(rèn)情況下,psycopg2JSONB 列返回為字符串。需注冊(cè)適配器實(shí)現(xiàn)自動(dòng)轉(zhuǎn)換:

import json
import psycopg2
from psycopg2.extras import Json

# 注冊(cè)自動(dòng)轉(zhuǎn)換:DB → Python
def _json_decode(data, cur):
    if data is None:
        return None
    return json.loads(data)

# 注冊(cè)適配器
psycopg2.extensions.register_type(
    psycopg2.extensions.new_type(
        (3802,), "JSONB", _json_decode  # 3802 是 JSONB 的 OID
    )
)

# 連接數(shù)據(jù)庫(kù)
conn = psycopg2.connect(
    host="localhost",
    database="mydb",
    user="user",
    password="pass"
)

3.2 插入 JSON 數(shù)據(jù)

data = {
    "user_id": 123,
    "action": "login",
    "metadata": {
        "ip": "192.168.1.1",
        "device": "mobile"
    }
}

cur = conn.cursor()
cur.execute(
    "INSERT INTO events (event_data) VALUES (%s)",
    (Json(data),)  # 使用 Json 包裝器
)
conn.commit()

注意:必須使用 psycopg2.extras.Json,否則會(huì)被當(dāng)作字符串插入。

3.3 查詢并自動(dòng)反序列化

cur.execute("SELECT id, event_data FROM events WHERE id = %s", (1,))
row = cur.fetchone()
print(type(row[1]))  # <class 'dict'>
print(row[1]['metadata']['ip'])  # 192.168.1.1

得益于前面的適配器注冊(cè),event_data 自動(dòng)轉(zhuǎn)為 dict。

3.4 復(fù)雜查詢示例

1、提取嵌套字段

cur.execute("""
    SELECT 
        id,
        event_data->>'action' AS action,
        event_data->'metadata'->>'ip' AS ip
    FROM events
    WHERE (event_data->'metadata'->>'device') = %s
""", ("mobile",))

for row in cur:
    print(f"Action: {row[1]}, IP: {row[2]}")

2、條件過(guò)濾(使用 @>)

# 查找包含特定子結(jié)構(gòu)的記錄
filter_condition = {"metadata": {"device": "mobile"}}
cur.execute(
    "SELECT * FROM events WHERE event_data @> %s",
    (Json(filter_condition),)
)

四、使用 asyncpg 處理 JSON(異步場(chǎng)景)

asyncpg 對(duì) JSONB 支持更友好,默認(rèn)自動(dòng)轉(zhuǎn)換。

4.1 基礎(chǔ)用法

import asyncio
import asyncpg

async def main():
    conn = await asyncpg.connect(
        host='localhost',
        database='mydb',
        user='user',
        password='pass'
    )

    # 插入:直接傳 dict
    data = {"user_id": 123, "tags": ["a", "b"]}
    await conn.execute(
        "INSERT INTO items (payload) VALUES ($1)",
        data  # asyncpg 自動(dòng)序列化為 JSONB
    )

    # 查詢:自動(dòng)反序列化為 dict/list
    row = await conn.fetchrow("SELECT payload FROM items LIMIT 1")
    print(type(row['payload']))  # <class 'dict'>
    print(row['payload']['tags'])  # ['a', 'b']

    await conn.close()

asyncio.run(main())

優(yōu)勢(shì):無(wú)需額外配置,開箱即用。

4.2 復(fù)雜查詢

# 使用路徑操作符
rows = await conn.fetch("""
    SELECT 
        id,
        payload->'user'->>'name' AS name
    FROM profiles
    WHERE payload @> $1
""", {"settings": {"visible": True}})

for r in rows:
    print(r['name'])

五、使用 SQLAlchemy ORM 處理 JSON

SQLAlchemy 通過(guò) JSONJSONB 類型提供 ORM 支持。

5.1 模型定義

from sqlalchemy import create_engine, Column, Integer
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

Base = declarative_base()

class Event(Base):
    __tablename__ = 'events'
    id = Column(Integer, primary_key=True)
    data = Column(JSONB)  # 使用 JSONB

engine = create_engine('postgresql://user:pass@localhost/mydb')
Session = sessionmaker(bind=engine)

5.2 CRUD 操作

session = Session()

# 插入
event = Event(data={
    "type": "click",
    "element": {"id": "btn1", "class": "primary"}
})
session.add(event)
session.commit()

# 查詢(自動(dòng)轉(zhuǎn)為 dict)
e = session.query(Event).first()
print(e.data['element']['id'])  # btn1

# 條件查詢(使用 .op() 調(diào)用操作符)
from sqlalchemy import text
results = session.query(Event).filter(
    Event.data.op('@>')({'type': 'click'})
).all()

5.3 使用專用函數(shù)(SQLAlchemy 1.4+)

from sqlalchemy.dialects.postgresql import JSONB

# 提取字段
session.query(
    Event.data['user']['name'].astext.label('username')
).all()

六、高級(jí)技巧與最佳實(shí)踐

6.1 動(dòng)態(tài)構(gòu)建 JSON 查詢條件

避免拼接 SQL,使用參數(shù)化:

def find_by_metadata(conn, **kwargs):
    # 構(gòu)建嵌套 dict
    condition = {"metadata": kwargs}
    cur = conn.cursor()
    cur.execute(
        "SELECT * FROM events WHERE event_data @> %s",
        (Json(condition),)
    )
    return cur.fetchall()

# 調(diào)用
results = find_by_metadata(conn, device="mobile", os="iOS")

6.2 更新 JSON 字段

# 使用 jsonb_set 更新嵌套字段
cur.execute("""
    UPDATE users 
    SET profile = jsonb_set(profile, %s, %s, true)
    WHERE id = %s
""", (
    ['settings', 'notifications'],  # 路徑(數(shù)組)
    Json({"email": True, "push": False}),  # 新值
    user_id
))

第四個(gè)參數(shù) true 表示:若路徑不存在則創(chuàng)建。

6.3 索引優(yōu)化

對(duì)高頻查詢字段建立 GIN 索引:

-- 全文索引(適用于任意鍵查詢)
CREATE INDEX idx_event_data ON events USING GIN (event_data);

-- 特定路徑索引(更高效)
CREATE INDEX idx_event_action ON events ((event_data->>'action'));

在 Python 中可通過(guò) Alembic 或原生 SQL 創(chuàng)建。

七、性能考量

7.1 存儲(chǔ)效率

  • JSONBJSON 節(jié)省 10%~30% 空間
  • 避免在 JSON 中存儲(chǔ)大文本(如 base64 圖片),應(yīng)存 URL

7.2 查詢性能

  • 避免在 WHERE 中對(duì) JSON 字段使用函數(shù)(如 length(data->>'name')),會(huì)導(dǎo)致索引失效
  • 優(yōu)先使用 @>, ?, ->> 等支持索引的操作符

7.3 批量操作

  • 使用 execute_values(psycopg2)或 copy_records_to_table(asyncpg)提升批量插入性能
  • 示例(psycopg2):
from psycopg2.extras import execute_values
data_list = [{"id": i, "tags": ["x"]} for i in range(1000)]
execute_values(
    cur,
    "INSERT INTO items (payload) VALUES %s",
    [(Json(d),) for d in data_list]
)

八、典型應(yīng)用場(chǎng)景

8.1 用戶配置存儲(chǔ)

CREATE TABLE user_settings (
    user_id INT PRIMARY KEY,
    preferences JSONB NOT NULL DEFAULT '{}'
);
  • 優(yōu)勢(shì):無(wú)需 ALTER TABLE 即可新增配置項(xiàng)
  • 查詢:SELECT preferences->'theme' FROM user_settings

8.2 日志與事件追蹤

  • 存儲(chǔ)非結(jié)構(gòu)化日志,支持按任意字段過(guò)濾
  • 結(jié)合 BRIN 索引按時(shí)間分區(qū),GIN 索引按內(nèi)容查詢

8.3 動(dòng)態(tài)表單/問(wèn)卷

  • 表單結(jié)構(gòu)存為 JSON,回答存為另一 JSON
  • 避免 EAV(Entity-Attribute-Value)反模式

九、常見陷阱與解決方案

9.1 時(shí)區(qū)與日期處理

JSON 不支持日期類型,通常存為 ISO 字符串:

data = {"created_at": datetime.utcnow().isoformat()}

查詢時(shí)用 to_timestamp() 轉(zhuǎn)換:

SELECT to_timestamp(data->>'created_at', 'YYYY-MM-DD"T"HH24:MI:SS.US') 
FROM logs;

9.2 精度丟失(浮點(diǎn)數(shù))

PostgreSQL 的 JSONB 使用 IEEE 754 雙精度,與 Python 一致,一般無(wú)問(wèn)題。
但若需高精度(如金融),應(yīng)存為字符串或使用 NUMERIC 字段。

9.3 鍵名大小寫敏感

JSON 對(duì)象鍵區(qū)分大小寫:

-- 以下不等價(jià)
data->'UserId'  vs  data->'userid'

建議統(tǒng)一使用小寫命名。

以上就是使用Python與PostgreSQL的JSON數(shù)據(jù)進(jìn)行交互的詳細(xì)內(nèi)容,更多關(guān)于Python與PostgreSQL JSON數(shù)據(jù)交互的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Django如何判斷訪問(wèn)來(lái)源是PC端還是手機(jī)端

    Django如何判斷訪問(wèn)來(lái)源是PC端還是手機(jī)端

    這篇文章主要介紹了Django如何判斷訪問(wèn)來(lái)源是PC端還是手機(jī)端問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • Python openpyxl模塊學(xué)習(xí)之輕松玩轉(zhuǎn)Excel

    Python openpyxl模塊學(xué)習(xí)之輕松玩轉(zhuǎn)Excel

    Python提供了許多操作Excel的模塊,能夠讓我們從繁瑣的工作中騰出雙手。本文主要為大家介紹的是openpyxl模塊,它的功能相對(duì)與其他模塊更為齊全,感興趣的小伙伴快來(lái)學(xué)習(xí)一下吧
    2021-12-12
  • 基于Python的ModbusTCP客戶端實(shí)現(xiàn)詳解

    基于Python的ModbusTCP客戶端實(shí)現(xiàn)詳解

    這篇文章主要介紹了基于Python的ModbusTCP客戶端實(shí)現(xiàn)詳解,Modbus Poll和Modbus Slave是兩款非常流行的Modbus設(shè)備仿真軟件,支持Modbus RTU/ASCII和Modbus TCP/IP協(xié)議 ,經(jīng)常用于測(cè)試和調(diào)試Modbus設(shè)備,觀察Modbus通信過(guò)程中的各種報(bào)文,需要的朋友可以參考下
    2019-07-07
  • 基于Python實(shí)現(xiàn)在線加密解密網(wǎng)站系統(tǒng)

    基于Python實(shí)現(xiàn)在線加密解密網(wǎng)站系統(tǒng)

    在這個(gè)數(shù)字化時(shí)代,數(shù)據(jù)的安全和隱私變得越來(lái)越重要,所以本文小編就來(lái)帶大家實(shí)現(xiàn)一個(gè)簡(jiǎn)單但功能強(qiáng)大的加密解密系統(tǒng),并深入探討它是如何工作的,有興趣的可以了解下
    2023-09-09
  • Python三維網(wǎng)格體素化實(shí)例

    Python三維網(wǎng)格體素化實(shí)例

    這篇文章主要介紹了Python三維網(wǎng)格體素化實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-06-06
  • Python推導(dǎo)式之字典推導(dǎo)式和集合推導(dǎo)式使用體驗(yàn)

    Python推導(dǎo)式之字典推導(dǎo)式和集合推導(dǎo)式使用體驗(yàn)

    這篇文章主要為大家介紹了Python推導(dǎo)式之字典推導(dǎo)式和集合推導(dǎo)式使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • python保存字符串到文件的方法

    python保存字符串到文件的方法

    這篇文章主要介紹了python保存字符串到文件的方法,實(shí)例分析了Python文件與字符串操作的相關(guān)技巧,需要的朋友可以參考下
    2015-07-07
  • 簡(jiǎn)單文件操作python 修改文件指定行的方法

    簡(jiǎn)單文件操作python 修改文件指定行的方法

    使用python進(jìn)行簡(jiǎn)略的文件讀寫
    2013-05-05
  • 介紹Python的@property裝飾器的用法

    介紹Python的@property裝飾器的用法

    這篇文章主要介紹了介紹Python的@property裝飾器的用法,是Python學(xué)習(xí)進(jìn)階中的重要知識(shí),代碼基于Python2.x版本,需要的朋友可以參考下
    2015-04-04
  • 利用Anaconda創(chuàng)建虛擬環(huán)境的全過(guò)程

    利用Anaconda創(chuàng)建虛擬環(huán)境的全過(guò)程

    因?yàn)槎啻沃匦屡渲铆h(huán)境,這些命令每次都要用,每次都忘記,需要重新搜索,所以記錄這一過(guò)程,下面這篇文章主要給大家介紹了關(guān)于利用Anaconda創(chuàng)建虛擬環(huán)境的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2022-07-07

最新評(píng)論

金乡县| 沁阳市| 江安县| 子长县| 江孜县| 金湖县| 安宁市| 吴桥县| 柳河县| 定陶县| 松原市| 黑水县| 利津县| 平远县| 荃湾区| 伊春市| 栾城县| 嫩江县| 泰安市| 淮安市| 双鸭山市| 桐城市| 洪江市| 涪陵区| 濮阳县| 霍林郭勒市| 盐边县| 晋中市| 云南省| 民权县| 磐石市| 吉首市| 庆城县| 九台市| 随州市| 布尔津县| 商洛市| 蒙阴县| 吐鲁番市| 北流市| 工布江达县|