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

如何在Rust sqlx中表示JSONB类型的字符串数组列?

解决sqlx中PostgreSQL JSONB数组映射到Vec的类型冲突问题

问题原因

sqlx的query_as!宏默认会将PostgreSQL的JSONB类型列解析为Option<JsonValue>,但你的结构体中tags字段定义为Vec<String>,导致类型不匹配,触发编译错误。

解决方案

不需要创建额外枚举,有两种直接可行的处理方式:


方式一:使用sqlx的Json<T>包装类型

修改结构体中tags字段的类型,用sqlx::Json包裹Vec<String>,让sqlx自动处理JSONB和Rust类型的映射:

use sqlx::{Json, FromRow};

#[derive(Deserialize, FromRow)]
pub struct Product {
    pub id: i32,
    pub product_id: i64,
    pub title: String,
    pub handle: Option<String>,
    pub tags: Json<Vec<String>>,
    pub product_type: Option<String>,
    pub image_url: String,
    pub created_at: String,
    pub updatedAt: String,
}

#[derive(Deserialize, FromRow)]
pub struct ProductPatch {
    pub product_id: i64,
    pub title: String,
    pub handle: Option<String>,
    pub tags: Json<Vec<String>>,
    pub product_type: Option<String>,
    pub image_url: String,
}

调整add_product函数的参数传递逻辑,避免unwrap()引发panic:

async fn add_product(
    pool: &Db,
    product: ProductPatch,
) -> Result<ProductPatch, sqlx::Error> {
    let rec = sqlx::query_as!(
        ProductPatch,
        r#"--sql
        INSERT INTO products (product_id, title, handle, tags, product_type, image_url)
        VALUES ($1, $2, $3, $4, $5, $6)
        RETURNING product_id, title, handle, tags, product_type, image_url
        "#,
        product.product_id,
        product.title,
        product.handle.as_ref(),
        product.tags,
        product.product_type.as_ref(),
        product.image_url
    )
    .fetch_one(pool)
    .await?;

    Ok(rec)
}

方式二:在query_as!中显式指定类型转换

如果不想修改结构体类型,可以在SQL语句中给tags字段添加类型注解,明确告诉query_as!将其解析为Vec<String>:

async fn add_product(
    pool: &Db,
    product: ProductPatch,
) -> Result<ProductPatch, sqlx::Error> {
    let rec = sqlx::query_as!(
        ProductPatch,
        r#"--sql
        INSERT INTO products (product_id, title, handle, tags, product_type, image_url)
        VALUES ($1, $2, $3, $4::jsonb, $5, $6)
        RETURNING 
            product_id, 
            title, 
            handle, 
            tags AS "tags!: Vec<String>",
            product_type, 
            image_url
        "#,
        product.product_id,
        product.title,
        product.handle.as_ref().unwrap_or(&""),
        &product.tags,
        product.product_type.as_ref().unwrap_or(&""),
        product.image_url
    )
    .fetch_one(pool)
    .await?;

    Ok(rec)
}

额外注意点

  • 避免直接用unwrap()处理Option类型,一旦字段值为None会导致程序panic,建议用as_ref().unwrap_or(&默认值)或者提前做非空校验。
  • 结构体需要派生FromRow trait,query_as!依赖这个trait完成查询结果到结构体的映射。

内容的提问来源于stack exchange,提问作者G.Rose

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 13:27:21