Golang中Datastore查询返回的数据与预期不符

Golang中Datastore查询返回的数据与预期不符 我是否应该期望迭代器能正确处理这个结构体的[]string属性。 数据库中有三个计划。

**计划1** ContinuingServiceTypes 和 InitialServiceTypes
{
  "values": [
    {
      "stringValue": "s1"
    },
    {
      "stringValue": "s2"
    },
    {
      "stringValue": "s3"
    }
  ]
}
**计划2** ContinuingServiceTypes 和 InitialServiceTypes
{
  "values": [
    {
      "stringValue": "s2"
    },
    {
      "stringValue": "s3"
    }
   ]
}
**计划2** ContinuingServiceTypes 和 InitialServiceTypes
{
  "values": [
    {
      "stringValue": "s3"
    }
   ]
}
type Plan struct {
	ContinuingDuration     int      `json:"continuingDuration"`
	ContinuingServiceTypes []string `json:"continuingServiceTypes"`
	InitialAssesment       bool     `json:"initialAssesment"`
	InitialDuration        int      `json:"continuingDuration"`
	InitialServiceTypes    []string `json:"initialServiceTypes"`
	OngoingMonitoring      bool     `json:"ongoingMonitoring"`
}
// goGetPlan 从数据存储返回计划实体数组用于测试
func goGetPlan(ts TherapistService) {
	var thePlan Plan
	query := datastore.NewQuery("Plan")
	items := ts.DSClient.Run(ts.Ctx, query)

	for {
		_, err := items.Next(&thePlan)
		if err == iterator.Done {
			break
		}
		if err != nil {
			log.Fatalf("Error fetching next Plan: %v", err)
		}
		log.Printf("The Plan %v  %v", thePlan.ContinuingServiceTypes, thePlan.InitialServiceTypes)
	}
}

日志语句的输出是: 计划1 [s1 s2 s3] [s1 s2 s3] 计划2 [s2 s3 s3] [s2 s3 s3] 计划3 [s3 s3 s3] [s3 s3 s3] 除非我在每次迭代后初始化[]string切片,这样输出才符合预期。我已经追踪源代码到了数据存储包的加载模块,但很遗憾后面就跟不上了。

这是我应该实现的代码类型,还是应该由库来处理?

感谢您可能提供的任何帮助。


更多关于Golang中Datastore查询返回的数据与预期不符的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

很高兴能帮助您

更多关于Golang中Datastore查询返回的数据与预期不符的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你好

你正在使用同一个Plan实例进行读取。由于每次读取的元素数量不同,有时会留下旧的元素。将plan的声明移到for循环内部,这样每次都会获得一个新的实例。

约翰,

非常感谢

我想我的老习惯让我一直注意内存消耗(垃圾回收机制出现之前的年代)。我已经采纳了您的建议。现在我对 query.go 和 load.go 有了更深入的了解。

再次感谢,

约翰

在Google Cloud Datastore中,当使用迭代器循环处理多个实体时,如果结构体包含切片字段,确实需要在每次迭代时重新初始化切片,否则会出现数据重复的问题。

这是因为Datastore客户端在反序列化数据时,会向现有切片追加数据而不是替换它。当处理多个实体时,如果不重置切片,之前实体的数据会累积到后续实体中。

以下是正确的实现方式:

func goGetPlan(ts TherapistService) {
    query := datastore.NewQuery("Plan")
    items := ts.DSClient.Run(ts.Ctx, query)

    for {
        var thePlan Plan
        _, err := items.Next(&thePlan)
        if err == iterator.Done {
            break
        }
        if err != nil {
            log.Fatalf("Error fetching next Plan: %v", err)
        }
        log.Printf("The Plan %v  %v", thePlan.ContinuingServiceTypes, thePlan.InitialServiceTypes)
    }
}

关键变化是将 var thePlan Plan 声明移到循环内部,这样每次迭代都会创建一个新的Plan实例,切片字段自然会被初始化为空的 []string

如果你需要在循环外部使用thePlan变量,可以显式重置切片:

func goGetPlan(ts TherapistService) {
    var thePlan Plan
    query := datastore.NewQuery("Plan")
    items := ts.DSClient.Run(ts.Ctx, query)

    for {
        // 重置切片
        thePlan.ContinuingServiceTypes = nil
        thePlan.InitialServiceTypes = nil
        
        _, err := items.Next(&thePlan)
        if err == iterator.Done {
            break
        }
        if err != nil {
            log.Fatalf("Error fetching next Plan: %v", err)
        }
        log.Printf("The Plan %v  %v", thePlan.ContinuingServiceTypes, thePlan.InitialServiceTypes)
    }
}

这是Datastore客户端库的预期行为,需要在应用层处理切片的重置。

回到顶部