PAYATHON 2026

Go MongoDB 查询无报错但 Recovery 结构体为空,如何排查?

数据小许

结论

先检查 GetPlayerRecoveryById 查询的集合。写入和更新操作使用 recoveryTableName,读取却使用 playersTableName。如果两个常量指向不同集合,查询可能会在玩家集合中找到 id 相同的文档。若该文档缺少 Recovery 所需的字段,解码后这些字段会保留零值;仅仅缺少字段不会导致解码报错。

将读取集合改为与写入时相同的 recoveryTableName:

func (db *NoSqlConnection[T]) GetPlayerRecoveryById(id T) (recovery.Recovery[T], error) {
	filter := bson.M{"id": id}
	res := recovery.Recovery[T]{}
	err := db.db.
		Collection(recoveryTableName).
		FindOne(context.TODO(), filter).
		Decode(&res)
	if err != nil {
		return res, err
	}
	return res, nil
}

为什么没有报错

CreateRecoveryTable 和 AddRecoveryRecord 都操作 recoveryTableName:前者插入 id,后者按 id 更新文档,并设置 game_id 和 record。原查询代码却使用了:

db.db.Collection(playersTableName).FindOne(context.TODO(), filter).Decode(&res)

只要 FindOne 在所选集合中找到符合 id 条件的文档,就会尝试解码。如果 BSON 文档缺少 Recovery[T] 中的 id 或 record 字段,这些字段可能保留零值。因此,没有解码错误并不能说明查询到的就是 recovery 记录。

修复后仍为空时

确认 recoveryTableName 的实际值与写入时完全相同,并检查目标集合中是否存在 id 匹配的文档。还要确认查询传入的 id 与存储值的 BSON 类型一致,例如两边不能一边使用字符串,另一边使用 UUID 或整数。

也可以先将结果解码为 bson.M,查看 MongoDB 实际返回的字段和值,再与 Recovery[T] 的 bson 标签核对:

var doc bson.M
err := db.db.
	Collection(recoveryTableName).
	FindOne(context.TODO(), bson.M{"id": id}).
	Decode(&doc)
if err != nil {
	return err
}
fmt.Printf("%#v\n", doc)

如果集合中的 record 是嵌套文档,Record any 可以承载解码结果,但实际 Go 值的类型取决于 BSON 解码方式。如果需要使用具体类型,应将字段声明为对应的结构体类型,并确认它的 bson 标签与文档字段匹配。

备注:内容仅供参考。