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

ScyllaDB查询报错:Cannot unmarshal timestamps into *string 求助

问题

在ScyllaDB中存储时间戳后,查询时触发错误:Cannot unmarshal timestamps into *string。开发Todo API时,从数据库获取Todo数据出现该问题,Todo结构体的CreatedAt和UpdatedAt字段类型为time.Time。

Todo结构体定义

type Todo struct {
    ID          gocql.UUID `json:"id"`
    UserID      string     `json:"user_id"`
    Title       string     `json:"title"`
    Description string     `json:"description"`
    Status      string     `json:"status"`
    CreatedAt   time.Time  `json:"created_at"`
    UpdatedAt   time.Time  `json:"updated_at"`
}

查询函数

func GetAllTodos(user_id string) ([]*Todo, error) {
    var todos []*Todo

    query := `SELECT * FROM todo WHERE user_id = ? ALLOW FILTERING`
    iter := Session.Query(query, user_id).Iter()

    var todo Todo
    for iter.Scan(&todo.ID, &todo.UserID, &todo.Title, &todo.Description, &todo.Status, &todo.CreatedAt, &todo.UpdatedAt) {      
        todos = append(todos, &todo)
        todo = Todo{}
    }

    if err := iter.Close(); err != nil {
        return nil, err
    }
    return todos, nil
}

已尝试的解决方法:

  • 创建string或*string类型变量,用time.Parse解析时间戳
  • 直接传入Todo结构体
  • 用time.Unix将纳秒时间戳转成毫秒(time.Unix(timeStr/1000,0))
    但以上方法均未解决问题,错误持续出现。

解决方案

1. 检查ScyllaDB表字段类型

确保todo表中created_at和updated_at字段类型为timestamp,而非text或其他字符串类型。如果字段类型是字符串,gocql驱动会尝试将其反序列化为string,与结构体的time.Time类型冲突。

查看表结构:

DESCRIBE TABLE todo;

若类型不符,修改表结构(注意备份数据):

ALTER TABLE todo ALTER created_at TYPE timestamp;
ALTER TABLE todo ALTER updated_at TYPE timestamp;

2. 升级gocql驱动版本

旧版本驱动处理time.Time可能存在兼容性问题,升级到最新稳定版:

go get github.com/gocql/gocql@latest

3. 显式指定查询字段顺序

SELECT *可能因表字段顺序与Scan参数顺序不匹配,导致驱动错误映射字段。修改查询语句为显式指定字段,确保顺序完全一致:

query := `SELECT id, user_id, title, description, status, created_at, updated_at FROM todo WHERE user_id = ? ALLOW FILTERING`

4. 直接扫描到结构体

gocql支持直接将结果扫描到结构体,避免字段顺序问题,代码更简洁:

func GetAllTodos(user_id string) ([]*Todo, error) {
    var todos []*Todo

    query := `SELECT id, user_id, title, description, status, created_at, updated_at FROM todo WHERE user_id = ? ALLOW FILTERING`
    iter := Session.Query(query, user_id).Iter()

    var todo Todo
    for iter.Scan(&todo) {      
        todos = append(todos, &todo)
        todo = Todo{}
    }

    if err := iter.Close(); err != nil {
        return nil, err
    }
    return todos, nil
}

若表字段名与结构体字段名不匹配,可通过db标签指定映射:

type Todo struct {
    ID          gocql.UUID `json:"id" db:"id"`
    UserID      string     `json:"user_id" db:"user_id"`
    // 其他字段同理
}

5. 自定义字符串时间戳解析(仅当字段为字符串类型时)

若无法修改表字段类型,需手动解析字符串时间戳:

func GetAllTodos(user_id string) ([]*Todo, error) {
    var todos []*Todo

    query := `SELECT id, user_id, title, description, status, created_at, updated_at FROM todo WHERE user_id = ? ALLOW FILTERING`
    iter := Session.Query(query, user_id).Iter()

    var (
        id          gocql.UUID
        userID      string
        title       string
        description string
        status      string
        createdAtStr string
        updatedAtStr string
    )

    for iter.Scan(&id, &userID, &title, &description, &status, &createdAtStr, &updatedAtStr) {
        createdAt, err := time.Parse(time.RFC3339, createdAtStr)
        if err != nil {
            return nil, err
        }
        updatedAt, err := time.Parse(time.RFC3339, updatedAtStr)
        if err != nil {
            return nil, err
        }
        todos = append(todos, &Todo{
            ID:          id,
            UserID:      userID,
            Title:       title,
            Description: description,
            Status:      status,
            CreatedAt:   createdAt,
            UpdatedAt:   updatedAt,
        })
    }

    if err := iter.Close(); err != nil {
        return nil, err
    }
    return todos, nil
}

内容的提问来源于stack exchange,提问作者Dhairya Srivastava

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 08:33:11