由于 Datastore 模拟器似乎没有导入功能,因此您可以构建自己的。
就像在脚本中创建两个客户端一样简单,一个用于远程(云)数据存储,一个用于本地数据存储模拟器。由于云客户端库支持模拟器,您可以深入研究代码以了解如何正确建立连接。
我正是为 go 云客户端库做的,并想出了这个脚本:
package main
import (
"context"
"fmt"
"os"
"time"
"cloud.google.com/go/datastore"
"google.golang.org/api/iterator"
"google.golang.org/api/option"
"google.golang.org/grpc"
)
const (
projectId = "<PROJECT_ID>"
namespace = "<NAMESPACE>"
kind = "<KIND>"
emulatorHost = "<EMULATOR_HOST>:<EMULATOR_PORT>"
)
func main() {
ctx := context.Background()
// Create the Cloud Datastore client
remoteClient, err := datastore.NewClient(ctx, projectId, option.WithGRPCConnectionPool(50))
if err != nil {
fmt.Fprintf(os.Stderr, "Could not create remote datastore client: %v \n", err)
}
// Create the local Datastore Emulator client
o := []option.ClientOption{
option.WithEndpoint(emulatorHost),
option.WithoutAuthentication(),
option.WithGRPCDialOption(grpc.WithInsecure()),
option.WithGRPCConnectionPool(50),
}
localClient, err := datastore.NewClient(ctx, projectId, o...)
if err != nil {
fmt.Fprintf(os.Stderr, "Could not create local datastore client: %v \n", err)
}
// Create the query
q := datastore.NewQuery(kind).Namespace(namespace)
//Run the query and handle the received entities
start := time.Now() // This is just to calculate the rate
for it, i := remoteClient.Run(ctx, q), 1; ; i++ {
x := &arbitraryEntity{}
// Get the entity
key, err := it.Next(x)
if err == iterator.Done {
break
}
if err != nil {
fmt.Fprintf(os.Stderr, "Error retrieving entity: %v \n", err)
}
// Insert the entity into the emulator
_, err = localClient.Put(ctx, key, x)
if err != nil {
fmt.Fprintf(os.Stderr, "Error saving entity: %v \n", err)
}
// Print stats
go fmt.Fprintf(os.Stdout, "\rCopied %v entities. Rate: %v/s", i, i/int(time.Since(start).Seconds()))
}
fmt.Fprintln(os.Stdout)
}
// Declare a struct capable of handling any type of entity.
// It implements the PropertyLoadSaver interface
type arbitraryEntity struct {
properties []datastore.Property
}
func (e *arbitraryEntity) Load(ps []datastore.Property) error {
e.properties = ps
return nil
}
func (e *arbitraryEntity) Save() ([]datastore.Property, error) {
return e.properties, nil
}
有了这个,我得到了大约 700 个实体/秒的速率,但它可能会根据您拥有的实体而发生很大变化。
不要设置 DATASTORE_EMULATOR_HOST 环境变量,因为脚本会手动创建与本地模拟器的连接,并且您希望库自动连接到 Cloud Datastore。
脚本可以大大改进:远程和本地都使用 GRPC,因此您可以使用一些原始魔法来避免对消息进行编码解码。使用批处理进行上传也会有所帮助,以及使用 Go 的并发技巧。您甚至可以通过编程方式获取命名空间和种类,因此您不需要为每个实体运行它。
但是,我认为这个简单的概念证明可以帮助您了解如何开发自己的工具来运行导入。