如何在 golang 中使用命名空间从数据存储中查询实体?

How to query a entity from datastore with Namespace In golang?

我正在开发一个多租户应用程序,我需要从 KIND 和特定命名空间查询特定用户。

我可以从默认 Namespace.the 包中获取值,我在这里使用的是 "google.golang.org/appengine/datastore"

q := datastore.NewQuery(ENTITYNAME).Filter("Name =", ed.Expense.Name)
    var expenses []ExpenseEntiry
    return q.GetAll(ed.Ctx, &expenses)

命名空间值不是查询的一部分(它不是查询的 属性)。命名空间来自您在执行查询时传递的上下文,例如至 Query.GetAll().

如果您有一个上下文(您将它传递给 q.GetAll()),您可以使用 appengine.Namespace() 函数创建一个具有给定命名空间的派生上下文。

例如:

ctx2, err := appengine.Namespace(ed.Ctx, "mynamespace")
// check err

并使用这个新上下文传递给 Query.GetAll():

return q.GetAll(ctx2, &expenses)

您很少需要创建具有不同名称空间的新上下文,ed.Ctx 应该已经是具有正确名称空间的上下文。因此,当/在哪里创建 ed.Ctx,您应该已经在那里应用了命名空间,这样就可以避免 "accidental" 暴露其他租户的数据(这是一个主要的安全问题)。

如果您使用的是旧库:google.golang.org/appengine/datastore,则需要使用命名空间创建上下文:

ctx2, err := appengine.Namespace(ed.Ctx, "mynamespace")
if err != nil {
    return err
}

但是您想要使用最新的库:cloud.google.com/go/datastore。命名空间可以直接在 Query 对象上设置。这是新的。然后,您必须 运行 使用 datastoreClient.Run(ctx, query) 的查询。

func deleteTestNamespace(ctx context.Context, namespaces string) error {

    dsClient, err := datastore.NewClient(ctx, log, datastore.Config{...})
    err := dsClient.DeleteMulti(ctx, keys[i:i+chunk])
    if err != nil {
        return err
    }
   
    var keys []*datastore.Key
    for _, kind := range envKinds {
        // Get all keys
        query := datastore.NewQuery(kind).KeysOnly().Namespace(namespace)
        it := dsClient.Run(ctx, query)
        for {
            var key datastore.Key
            _, err := it.Next(&key)
            if err == iterator.Done {
                break
            }
            if err != nil {
                return err
            }
            keys = append(keys, &key)
        }

        // Delete all records in chunks of 500 or less
        for i := 0; i < len(keys); i += 500 {
            chunk := min(len(keys)-i, 500)
            err := dsClient.DeleteMulti(ctx, keys[i:i+chunk])
            if err != nil {
                return err
            }
        }
    }

    return nil

}

func min(num1 int, num2 int) int {
    if num1 < num2 {
        return num1
    }
    return num2
}