Rust+SurrealDB调用create方法报错:期望字符串却得到map
Rust + SurrealDB create方法类型不匹配错误解决
问题概述
使用Rust官方SDK调用SurrealDB的create方法时,持续触发类型不匹配错误:"invalid type: map expected a string",无论是否传入Todo结构体内容都会报错。
错误信息
初始写法报错:
Err(Api(FromValue { value: Array(Array([Object(Object({"completed": Bool(false), "content": Strand(Strand("Teste content")), "createdAt": Strand(Strand("2023-12-06T11:51:13.110266200Z")), "id": Thing(Thing { tb: "todo", id: String("47f46af4-27e8-4c22-9711-f49b9a866e82") }), "title": Strand(Strand("Teste")), "updatedAt": Strand(Strand("2023-12-06T11:51:13.110266200Z"))}))])), error: "invalid type: map, expected a string" }))
简化写法后报错:
Err(Api(FromValue { value: Array(Array([Object(Object({"id": Thing(Thing { tb: "todo", id: String("08kipc79181usjbuxlnu") })}))])), error: "invalid type: map, expected a string" }))
相关代码片段
仓库中create方法初始写法
// todo_repository.rs pub async fn create(&self, content: Todo) -> Result<Vec<Todo>, Error> { let record = DB.create(&self.table).content(content).await?; Ok(record) }
排查用的简化写法
// todo_repository.rs pub async fn create(&self, content: Todo) -> Result<Vec<Todo>, Error> { let record = DB.create("todo").await?; Ok(record) }
数据库连接配置
// surreal_context.rs pub static DB: Lazy<Surreal<Client>> = Lazy::new(Surreal::init); pub async fn connect_db() -> Result<()> { let _ = DB.connect::<Ws>("localhost:8000").await?; let _ = DB.signin(Root { username: "root", password: "root", }) .await; let _ = DB.use_ns("todo").use_db("todo").await?; Ok(()) } // main.rs #[tokio::main] async fn main() { let _ = connect_db().await; ... }
最小复现代码
#![allow(unused)] use chrono::{DateTime, Utc}; use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; use surrealdb::{Surreal, Result, engine::remote::ws::{Client, Ws}, opt::auth::Root}; #[allow(non_snake_case)] #[derive(Debug, Deserialize, Serialize, Clone)] pub struct Todo { pub id: Option<String>, pub title: String, pub content: String, pub completed: Option<bool>, pub createdAt: Option<DateTime<Utc>>, pub updatedAt: Option<DateTime<Utc>>, } pub static DB: Lazy<Surreal<Client>> = Lazy::new(Surreal::init); pub async fn connect() -> Result<()> { let _ = DB.connect::<Ws>("localhost:8000").await?; let _ = DB.signin(Root { username: "root", password: "root", }) .await; let _ = DB.use_ns("todo").use_db("todo").await?; Ok(()) } #[tokio::main] async fn main() -> Result<()> { let _ = connect().await; let record: Vec<Todo> = DB.create("todo").await?; Ok(()) }
依赖配置
[dependencies] axum = "0.7.1" chrono = { version = "0.4.31", features = ["serde"] } once_cell = "1.18.0" serde = { version = "1.0.193", features = ["derive"] } serde_json = "1.0.108" surrealdb = "1.0.0" tokio = { version = "1.34.0", features = ["full"] } tower-http = { version = "0.5.0", features = ["cors"] } uuid = { version = "1.6.1", features = ["v4", "serde"] }
解决方案
错误根源是**Todo结构体的id字段类型不匹配**:SurrealDB返回的id是Thing类型(包含表名和ID字符串的复合结构),但结构体中定义为Option<String>,导致反序列化时类型转换失败。
修复步骤:
- 导入SurrealDB的
Thing类型:use surrealdb::sql::Thing; - 修改
Todo结构体的id字段类型为Option<Thing>
修改后的Todo结构体:
#[allow(non_snake_case)] #[derive(Debug, Deserialize, Serialize, Clone)] pub struct Todo { pub id: Option<Thing>, pub title: String, pub content: String, pub completed: Option<bool>, pub createdAt: Option<DateTime<Utc>>, pub updatedAt: Option<DateTime<Utc>>, }
- 如果需要将
Thing转为字符串使用,可以调用Thing::to_string()方法,例如:
if let Some(id) = &todo.id { let id_str = id.to_string(); // 使用id_str }
另外,确保在调用create方法时传入正确的Todo实例(带title和content必填字段):
// 示例调用 let new_todo = Todo { id: None, title: "Teste".to_string(), content: "Teste content".to_string(), completed: Some(false), createdAt: None, // SurrealDB可自动生成,也可手动设置 updatedAt: None, }; let records: Vec<Todo> = DB.create("todo").content(new_todo).await?;
内容的提问来源于stack exchange,提问作者Vitor Lacerda
相关产品推荐
相关产品推荐

