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
相关产品推荐
相关产品推荐

