数据存储区包

import "google.golang.org/appengine/datastore"

简介

数据存储区包为 App Engine 的数据存储区服务提供了一个客户端。

基本运算

实体是存储单元,与键相关联。 键由一个可选的父键、一个字符串应用 ID、一个键类型(也称为实体类型)以及一个 StringID 或 IntID 组成。StringID 也称为实体名称或键名称。

可以创建一个 StringID 为零、IntID 为零的键;该键称为不完整键,而且不引用任何已保存的实体。 将一个实体放入数据存储区的不完整键下将导致系统为该实体生成具有非零 IntID 的唯一键。

一个实体的内容是从区分大小写的字段名称到值的映射。 有效的值类型包括:

- signed integers (int, int8, int16, int32 and int64),
- bool,
- string,
- float32 and float64,
- []byte (up to 1 megabyte in length),
- any type whose underlying type is one of the above predeclared types,
- ByteString,
- *Key,
- time.Time (stored with microsecond precision),
- appengine.BlobKey,
- appengine.GeoPoint,
- structs whose fields are all valid value types,
- slices of any of the above.

结构体切片是有效的,包含切片的结构体也是如此。 但是,如果一个结构体包含另一个结构体,则最多只能重复其中一个结构体。这样就不会产生以递归方式定义的结构体类型:任何(直接或间接)包含 []T 的结构体 T。

Get 和 Put 函数会加载并保存实体的内容。 实体的内容通常由结构体指针表示。

示例代码:

type Entity struct {
    Value string
}

func handle(w http.ResponseWriter, r *http.Request) {
    ctx := appengine.NewContext(r)

    k := datastore.NewKey(ctx, "Entity", "stringID", 0, nil)
    e := new(Entity)
    if err := datastore.Get(ctx, k, e); err != nil {
        http.Error(w, err.Error(), 500)
        return
    }

    old := e.Value
    e.Value = r.URL.Path

    if _, err := datastore.Put(ctx, k, e); err != nil {
        http.Error(w, err.Error(), 500)
        return
    }

    w.Header().Set("Content-Type", "text/plain; charset=utf-8")
    fmt.Fprintf(w, "old=%q\nnew=%q\n", old, e.Value)
}

GetMulti、PutMulti 和 DeleteMulti 分别是 Get、Put 和 Delete 函数的批处理版本。 其采用的是 []*Key 而不是 *Key,而且在遇到部分失败时可能会返回 appengine.MultiError。

属性

实体的内容可以用各种类型表示。 这些类型通常是结构体指针,但也可以是实现 PropertyLoadSaver 接口的任何类型。如果您使用结构体指针,则不必显式实现 PropertyLoadSaver 接口;数据存储区将通过反射自动转换。如果结构体指针确实实现了该接口,则系统将优先使用这些方法,而不是结构体指针的默认行为。结构体指针的类型更强,更易于使用;PropertyLoadSavers 更灵活。

传递的实际类型不必在 Get 和 Put 调用之间匹配,甚至不必在不同的 App Engine 请求之间匹配。 可以放置 *PropertyList 并获取与 *myStruct 相同的实体,也可以放置 *myStruct0 并获取 *myStruct1。 从概念上讲,任何实体都保存为一系列属性,并且会按属性逐个地加载到目标值中。 加载到结构体指针时,无法完全表示的实体(例如缺少的字段)将导致 ErrFieldMismatch 错误,但由调用者决定此错误是严重错误、可恢复错误还是可忽略错误。

默认情况下,对于结构体指针,所有属性都可能被编入索引,并且属性名称与字段名称相同(因此字段名称必须以大写字母开头)。 字段可能包含一个 `datastore:"name,options"` 标记。标记名称是属性名称,必须是由“.”连接的一个或多个有效 Go 标识符,但可以在开头使用小写字母。如果标记名称为空,则表示只使用字段名称。如果标记名称为“-”,则表示数据存储区将忽略该字段。如果选项为“noindex”,则表示字段将不会被编入索引。 如果选项为“”,则表示逗号可能会被省略。 没有其他识别的选项。

默认情况下,字段([]byte 除外)会被编入索引。 长度超过 1500 字节的字符串无法被编入索引;用于存储长字符串的字段应带有“noindex”标记。同样,长度超过 1500 字节的 ByteStrings 无法被编入索引。

示例代码:

// A and B are renamed to a and b.
// A, C and J are not indexed.
// D's tag is equivalent to having no tag at all (E).
// I is ignored entirely by the datastore.
// J has tag information for both the datastore and json packages.
type TaggedStruct struct {
    A int `datastore:"a,noindex"`
    B int `datastore:"b"`
    C int `datastore:",noindex"`
    D int `datastore:""`
    E int
    I int `datastore:"-"`
    J int `datastore:",noindex" json:"j"`
}

结构化属性

如果指向的结构体包含其他结构体,则嵌套或嵌入的结构体会被展平。 例如,给定下列定义:

type Inner1 struct {
    W int32
    X string
}

type Inner2 struct {
    Y float64
}

type Inner3 struct {
    Z bool
}

type Outer struct {
    A int16
    I []Inner1
    J Inner2
    Inner3
}

然后,Outer 的属性将等同于以下结构体的属性:

type OuterEquivalent struct {
    A     int16
    IDotW []int32  `datastore:"I.W"`
    IDotX []string `datastore:"I.X"`
    JDotY float64  `datastore:"J.Y"`
    Z     bool
}

如果 Outer 的嵌入 Inner3 字段已标记为 `datastore:"Foo"`,则等效字段将为:FooDotZ bool `datastore:"Foo.Z"`。

如果外部结构体标记为“noindex”,则其所有隐式展平字段实际上是“noindex”。

PropertyLoadSaver 接口

实体的内容也可以由实现 PropertyLoadSaver 接口的任何类型表示。 此类型可能是结构体指针,但并非必须是结构体指针。获取实体的内容时,数据存储区包将调用 Load;而在放置实体内容时,数据存储区包会调用 Save。 可能的用途包括提取非存储字段、验证字段或者只有在字段值为正数时才将字段编入索引。

示例代码:

type CustomPropsExample struct {
    I, J int
    // Sum is not stored, but should always be equal to I + J.
    Sum int `datastore:"-"`
}

func (x *CustomPropsExample) Load(ps []datastore.Property) error {
    // Load I and J as usual.
    if err := datastore.LoadStruct(x, ps); err != nil {
        return err
    }
    // Derive the Sum field.
    x.Sum = x.I + x.J
    return nil
}

func (x *CustomPropsExample) Save() ([]datastore.Property, error) {
    // Validate the Sum field.
    if x.Sum != x.I + x.J {
        return errors.New("CustomPropsExample has inconsistent sum")
    }
    // Save I and J as usual. The code below is equivalent to calling
    // "return datastore.SaveStruct(x)", but is done manually for
    // demonstration purposes.
    return []datastore.Property{
        {
            Name:  "I",
            Value: int64(x.I),
        },
        {
            Name:  "J",
            Value: int64(x.J),
        },
    }
}

*PropertyList 类型可以实现 PropertyLoadSaver,因此可以保存任意实体的内容。

查询

查询会根据其属性或键的祖先检索实体。 运行查询会生成结果迭代器:键或(键,实体)对。 查询可重复使用,您可以安全地调用 Query。此外,可从并发 Goroutine 运行查询。迭代器对于并发使用不安全。

查询是不可变的,可以通过调用 NewQuery 来创建,也可以通过调用返回新查询值的 Filter 或 Order 等方法从现有查询派生。 通常,可通过依次调用 NewQuery 以及零个或多个此类方法的链来构造查询。这些方法包括:

- Ancestor and Filter constrain the entities returned by running a query.
- Order affects the order in which they are returned.
- Project constrains the fields returned.
- Distinct de-duplicates projected entities.
- KeysOnly makes the iterator return only keys, not (key, entity) pairs.
- Start, End, Offset and Limit define which sub-sequence of matching entities
  to return. Start and End take cursors, Offset and Limit take integers. Start
  and Offset affect the first result, End and Limit affect the last result.
  If both Start and Offset are set, then the offset is relative to Start.
  If both End and Limit are set, then the earliest constraint wins. Limit is
  relative to Start+Offset, not relative to End. As a special case, a
  negative limit means unlimited.

示例代码:

type Widget struct {
    Description string
    Price       int
}

func handle(w http.ResponseWriter, r *http.Request) {
    ctx := appengine.NewContext(r)
    q := datastore.NewQuery("Widget").
        Filter("Price <", 1000).
        Order("-Price")
    b := new(bytes.Buffer)
    for t := q.Run(ctx); ; {
        var x Widget
        key, err := t.Next(&x)
        if err == datastore.Done {
            break
        }
        if err != nil {
            serveError(ctx, w, err)
            return
        }
        fmt.Fprintf(b, "Key=%v\nWidget=%#v\n\n", key, x)
    }
    w.Header().Set("Content-Type", "text/plain; charset=utf-8")
    io.Copy(w, b)
}

事务

RunInTransaction 在事务中运行一个函数。

示例代码:

type Counter struct {
    Count int
}

func inc(ctx context.Context, key *datastore.Key) (int, error) {
    var x Counter
    if err := datastore.Get(ctx, key, &x); err != nil && err != datastore.ErrNoSuchEntity {
        return 0, err
    }
    x.Count++
    if _, err := datastore.Put(ctx, key, &x); err != nil {
        return 0, err
    }
    return x.Count, nil
}

func handle(w http.ResponseWriter, r *http.Request) {
    ctx := appengine.NewContext(r)
    var count int
    err := datastore.RunInTransaction(ctx, func(ctx context.Context) error {
        var err1 error
        count, err1 = inc(ctx, datastore.NewKey(ctx, "Counter", "singleton", 0, nil))
        return err1
    }, nil)
    if err != nil {
        serveError(ctx, w, err)
        return
    }
    w.Header().Set("Content-Type", "text/plain; charset=utf-8")
    fmt.Fprintf(w, "Count=%d", count)
}

元数据

数据存储区包提供 App Engine 的某些数据存储区元数据的访问权限。 此元数据包含有关数据存储区中的实体组、命名空间、实体种类和属性的信息,以及每个属性的属性表示形式。

示例代码:

func handle(w http.ResponseWriter, r *http.Request) {
    // Print all the kinds in the datastore, with all the indexed
    // properties (and their representations) for each.
    ctx := appengine.NewContext(r)

    kinds, err := datastore.Kinds(ctx)
    if err != nil {
        serveError(ctx, w, err)
        return
    }

    w.Header().Set("Content-Type", "text/plain; charset=utf-8")
    for _, kind := range kinds {
        fmt.Fprintf(w, "%s:\n", kind)
        props, err := datastore.KindProperties(ctx, kind)
        if err != nil {
            fmt.Fprintln(w, "\t(unable to retrieve properties)")
            continue
        }
        for p, rep := range props {
            fmt.Fprintf(w, "\t-%s (%s)\n", p, strings.Join(", ", rep))
        }
    }
}

索引

Variables
func AllocateIDs(c context.Context, kind string, parent *Key, n int) (low, high int64, err error)
func Delete(c context.Context, key *Key) error
func DeleteMulti(c context.Context, key []*Key) error
func Get(c context.Context, key *Key, dst interface{}) error
func GetMulti(c context.Context, key []*Key, dst interface{}) error
func KindProperties(ctx context.Context, kind string) (map[string][]string, error)
func Kinds(ctx context.Context) ([]string, error)
func LoadStruct(dst interface{}, p []Property) error
func Namespaces(ctx context.Context) ([]string, error)
func Put(c context.Context, key *Key, src interface{}) (*Key, error)
func PutMulti(c context.Context, key []*Key, src interface{}) ([]*Key, error)
func RunInTransaction(c context.Context, f func(tc context.Context) error, opts *TransactionOptions) error
func SaveStruct(src interface{}) ([]Property, error)
type ByteString
type Cursor
    func DecodeCursor(s string) (Cursor, error)
    func (c Cursor) String() string
type Entity
type ErrFieldMismatch
    func (e *ErrFieldMismatch) Error() string
type Iterator
    func (t *Iterator) Cursor() (Cursor, error)
    func (t *Iterator) Next(dst interface{}) (*Key, error)
type Key
    func DecodeKey(encoded string) (*Key, error)
    func NewIncompleteKey(c context.Context, kind string, parent *Key) *Key
    func NewKey(c context.Context, kind, stringID string, intID int64, parent *Key) *Key
    func (k *Key) AppID() string
    func (k *Key) Encode() string
    func (k *Key) Equal(o *Key) bool
    func (k *Key) GobDecode(buf []byte) error
    func (k *Key) GobEncode() ([]byte, error)
    func (k *Key) Incomplete() bool
    func (k *Key) IntID() int64
    func (k *Key) Kind() string
    func (k *Key) MarshalJSON() ([]byte, error)
    func (k *Key) Namespace() string
    func (k *Key) Parent() *Key
    func (k *Key) String() string
    func (k *Key) StringID() string
    func (k *Key) UnmarshalJSON(buf []byte) error
type Property
type PropertyList
    func (l *PropertyList) Load(p []Property) error
    func (l *PropertyList) Save() ([]Property, error)
type PropertyLoadSaver
type Query
    func NewQuery(kind string) *Query
    func (q *Query) Ancestor(ancestor *Key) *Query
    func (q *Query) Count(c context.Context) (int, error)
    func (q *Query) Distinct() *Query
    func (q *Query) End(c Cursor) *Query
    func (q *Query) EventualConsistency() *Query
    func (q *Query) Filter(filterStr string, value interface{}) *Query
    func (q *Query) GetAll(c context.Context, dst interface{}) ([]*Key, error)
    func (q *Query) KeysOnly() *Query
    func (q *Query) Limit(limit int) *Query
    func (q *Query) Offset(offset int) *Query
    func (q *Query) Order(fieldName string) *Query
    func (q *Query) Project(fieldNames ...string) *Query
    func (q *Query) Run(c context.Context) *Iterator
    func (q *Query) Start(c Cursor) *Query
type TransactionOptions

变量

var (
    // ErrInvalidEntityType is returned when functions like Get or Next are
    // passed a dst or src argument of invalid type.
    ErrInvalidEntityType = errors.New("datastore: invalid entity type")
    // ErrInvalidKey is returned when an invalid key is presented.
    ErrInvalidKey = errors.New("datastore: invalid key")
    // ErrNoSuchEntity is returned when no entity was found for a given key.
    ErrNoSuchEntity = errors.New("datastore: no such entity")
)
var Done = errors.New("datastore: query has no more results")

查询迭代完成时将返回 Done。

var ErrConcurrentTransaction = errors.New("datastore: concurrent transaction")

如果事务因与并发事务冲突而回滚,则系统将返回 ErrConcurrentTransaction。

func AllocateIDs

func AllocateIDs(c context.Context, kind string, parent *Key, n int) (low, high int64, err error)

AllocateIDs 会返回整数 ID 的范围,其中包含 n 个由指定 kind 和 parent 组合而成的 ID。kind 不能为空;parent 可能为 nil。 数据存储区的自动 ID 序列生成器将不会使用所返回范围中的 ID,但这些 ID 可以与 NewKey 一起使用而不会产生冲突。

范围含下限值,但不含上限值。 换句话说,有效的 intIDs x 满足以下条件:“下限值 <= x && x < 上限值”。

如果没有返回错误,则“下限值 + n == 上限值”。

func Delete

func Delete(c context.Context, key *Key) error

Delete 会删除给定键的实体。

func DeleteMulti

func DeleteMulti(c context.Context, key []*Key) error

DeleteMulti 是 Delete 的批处理版本。

func Get

func Get(c context.Context, key *Key, dst interface{}) error

Get 会将为 k 存储的实体加载到 dst 中,而 dst 必须是结构体指针,或者必须实现 PropertyLoadSaver。 如果该键没有此类实体,则 Get 会返回 ErrNoSuchEntity。

dst 的不匹配结构体字段的值不会被修改,而且匹配的切片类型字段在附加到这些字段之前不会被重置。 具体来说,建议在每次进行 Get 调用时将指针传递给零值结构体。

将字段加载到与其先前存储类型不同的类型时,或者字段在目标结构体中缺失或未导出时,系统将返回 ErrFieldMismatch。 只有在 dst 是结构体指针时,才会返回 ErrFieldMismatch。

func GetMulti

func GetMulti(c context.Context, key []*Key, dst interface{}) error

GetMulti 是 Get 的批处理版本。

对于以下类型,dst 必须是 []S、[]*S、[]I 或 []P:某些结构体类型 S、某些接口类型 I 或某些非接口非指针类型 P(使得 P 或 *P 可以实现 PropertyLoadSaver)。 如果 dst 为 []I,则对于 Get,每个元素必须是有效的 dst:dst 必须是结构体指针,或者必须实现 PropertyLoadSaver。

特殊情况下,PropertyList 是 dst 的无效类型,即使 PropertyList 是结构体的切片。 PropertyList 会被视为无效,以免在本应传递 []PropertyList 时被错误传递。

func KindProperties

func KindProperties(ctx context.Context, kind string) (map[string][]string, error)

KindProperties 会返回所有已编入索引的给定种类的属性。 属性以属性名称到表示形式类型切片的映射形式返回。 受支持的 Go 属性类型的表示形式类型如下:

"INT64":     signed integers and time.Time
"DOUBLE":    float32 and float64
"BOOLEAN":   bool
"STRING":    string, []byte and ByteString
"POINT":     appengine.GeoPoint
"REFERENCE": *Key
"USER":      (not used in the Go runtime)

func Kinds

func Kinds(ctx context.Context) ([]string, error)

Kinds 会返回当前命名空间中所有种类的名称。

func LoadStruct

func LoadStruct(dst interface{}, p []Property) error

LoadStruct 会将属性从 p 加载到 dst。dst 必须是结构体指针。

func Namespaces

func Namespaces(ctx context.Context) ([]string, error)

Namespaces 会返回所有数据存储区命名空间。

func Put

func Put(c context.Context, key *Key, src interface{}) (*Key, error)

Put 会将实体 src 保存到键为 k 的数据存储区。src 必须是结构体指针,或者必须实现 PropertyLoadSaver;如果 src 是结构体指针,则系统将跳过该结构体的任何未导出字段。 如果 k 是不完整的键,则所返回的键会是数据存储区生成的唯一键。

func PutMulti

func PutMulti(c context.Context, key []*Key, src interface{}) ([]*Key, error)

PutMulti 是 Put 的批处理版本。

src 必须满足与 GetMulti 的 dst 参数相同的条件。

func RunInTransaction

func RunInTransaction(c context.Context, f func(tc context.Context) error, opts *TransactionOptions) error

RunInTransaction 在事务中运行 f。 它在 f 应该用于所有 App Engine 操作的事务上下文 tc 中调用 f。

如果 f 返回 nil,则 RunInTransaction 会尝试提交事务,如果成功,则返回 nil。 如果因事务冲突而导致提交失败,则 RunInTransaction 会重新尝试运行 f,并且每次都使用新的事务上下文。如果三次尝试均失败,RunInTransaction 将放弃尝试,并返回 ErrConcurrentTransaction。可以通过指定 TransactionOptions.Attempts 来配置尝试次数。

如果 f 返回非 nil,则所有数据存储区更改都将不会应用,而 RunInTransaction 会返回相同的错误。 函数 f 不会重试。

请注意,在 f 返回时,事务尚未提交。 调用代码时必须谨慎,直到 RunInTransaction 返回 nil 后,才能假设 f 的所有更改都已经提交。

由于 f 可能被调用多次,因此 f 通常应该具有幂等性。 datastore.Get 在分解切片字段时不是幂等的。

不支持使用嵌套的事务;c 不能用作事务上下文。

func SaveStruct

func SaveStruct(src interface{}) ([]Property, error)

SaveStruct 会将 src 中的属性以属性切片的形式返回。 src 必须是结构体指针。

type ByteString

type ByteString []byte

ByteString 是可以编入索引的短字节切片(最多 1500 字节)。

type Cursor

type Cursor struct {
    // contains filtered or unexported fields
}

Cursor 是迭代器的位置, 可以与不透明字符串进行相互转换。您可以通过不同的 HTTP 请求使用游标,但游标只能用于具有相同种类、祖先、过滤条件和顺序限制条件的查询。

func DecodeCursor

func DecodeCursor(s string) (Cursor, error)

Decode 通过游标的 Base-64 字符串表示形式对游标进行解码。

func (Cursor) String

func (c Cursor) String() string

String 会返回游标的 Base-64 字符串表示形式。

type Entity

type Entity struct {
    Key        *Key
    Properties []Property
}

Entity 是嵌套结构体的值类型。 此类型仅用于 Property 的值。

type ErrFieldMismatch

type ErrFieldMismatch struct {
    StructType reflect.Type
    FieldName  string
    Reason     string
}

将字段加载到与其先前存储类型不同的类型时,或者字段在目标结构体中缺失或未导出时,系统将返回 ErrFieldMismatch。 StructType 是传递给 Get 或 Iterator.Next 的目标参数所指向的结构体的类型。

func (*ErrFieldMismatch) Error

func (e *ErrFieldMismatch) Error() string

type Iterator

type Iterator struct {
    // contains filtered or unexported fields
}

Iterator 是运行查询的结果。

func (*Iterator) Cursor

func (t *Iterator) Cursor() (Cursor, error)

Cursor 会返回迭代器当前位置的游标。

func (*Iterator) Next

func (t *Iterator) Next(dst interface{}) (*Key, error)

Next 会返回下一个结果的键。 如果没有更多结果,Next 会将 Done 作为错误返回。

如果查询不只是键,而且 dst 是非 nil,则 Next 还会将为该键存储的实体加载到结构体指针或 PropertyLoadSaver dst 中,该函数的语义与 Get 函数相同,也可能会发生与 Get 函数相同的错误。

type Key

type Key struct {
    // contains filtered or unexported fields
}

Key 表示存储实体的数据存储区键,并且是不可变的。

func DecodeKey

func DecodeKey(encoded string) (*Key, error)

DecodeKey 会通过 Encode 所返回的不透明表示法对键进行解码。

func NewIncompleteKey

func NewIncompleteKey(c context.Context, kind string, parent *Key) *Key

NewIncompleteKey 会创建一个新的不完整键。 kind 不能为空。

func NewKey

func NewKey(c context.Context, kind, stringID string, intID int64, parent *Key) *Key

NewKey 会创建一个新键。 kind 不能为空。 stringID 和/或 intID 必须为零。 如果两者都为零,则表示所返回的键是不完整的。 parent 必须是完整的键或者 nil。

func (*Key) AppID

func (k *Key) AppID() string

AppID 会返回键的应用 ID。

func (*Key) Encode

func (k *Key) Encode() string

Encode 会返回适合在 HTML 和网址中使用的键的不透明表示形式。这与 Python 和 Java 运行时兼容。

func (*Key) Equal

func (k *Key) Equal(o *Key) bool

Equal 会返回用于判断两个键是否相同的布尔值。

func (*Key) GobDecode

func (k *Key) GobDecode(buf []byte) error

func (*Key) GobEncode

func (k *Key) GobEncode() ([]byte, error)

func (*Key) Incomplete

func (k *Key) Incomplete() bool

Incomplete 会返回用于判断键是否未引用存储实体的布尔值。 具体来说,就是该键的 StringID 和 IntID 是否为零。

func (*Key) IntID

func (k *Key) IntID() int64

IntID 会返回键的整数 ID(可能是 0)。

func (*Key) Kind

func (k *Key) Kind() string

Kind 会返回键的种类(也称为实体类型)。

func (*Key) MarshalJSON

func (k *Key) MarshalJSON() ([]byte, error)

func (*Key) Namespace

func (k *Key) Namespace() string

Namespace 会返回键的命名空间。

func (*Key) Parent

func (k *Key) Parent() *Key

Parent 会返回键的父键(可能是 nil)。

func (*Key) String

func (k *Key) String() string

String 会返回键的字符串表示形式。

func (*Key) StringID

func (k *Key) StringID() string

StringID 会返回键的字符串 ID(也称为实体名称或键名称,可能是 "")。

func (*Key) UnmarshalJSON

func (k *Key) UnmarshalJSON(buf []byte) error

type Property

type Property struct {
    // Name is the property name.
    Name string
    // Value is the property value. The valid types are:
    //    - int64
    //    - bool
    //    - string
    //    - float64
    //    - ByteString
    //    - *Key
    //    - time.Time
    //    - appengine.BlobKey
    //    - appengine.GeoPoint
    //    - []byte (up to 1 megabyte in length)
    //    - *Entity (representing a nested struct)
    // This set is smaller than the set of valid struct field types that the
    // datastore can load and save. A Property Value cannot be a slice (apart
    // from []byte); use multiple Properties instead. Also, a Value's type
    // must be explicitly on the list above; it is not sufficient for the
    // underlying type to be on that list. For example, a Value of "type
    // myInt64 int64" is invalid. Smaller-width integers and floats are also
    // invalid. Again, this is more restrictive than the set of valid struct
    // field types.
    //
    // A Value will have an opaque type when loading entities from an index,
    // such as via a projection query. Load entities into a struct instead
    // of a PropertyLoadSaver when using a projection query.
    //
    // A Value may also be the nil interface value; this is equivalent to
    // Python's None but not directly representable by a Go struct. Loading
    // a nil-valued property into a struct will set that field to the zero
    // value.
    Value interface{}
    // NoIndex is whether the datastore cannot index this property.
    NoIndex bool
    // Multiple is whether the entity can have multiple properties with
    // the same name. Even if a particular instance only has one property with
    // a certain name, Multiple should be true if a struct would best represent
    // it as a field of type []T instead of type T.
    Multiple bool
}

Property 是名称/值对以及一些元数据。 数据存储区实体的内容会加载并保存为一系列属性。一个实体可以具有多个同名的属性,前提是 p.Multiple 在该实体的所有同名属性中均为 true。

type PropertyList

type PropertyList []Property

PropertyList 会转换 []Property 以实现 PropertyLoadSaver。

func (*PropertyList) Load

func (l *PropertyList) Load(p []Property) error

Load 会将所有提供的属性加载到 l 中, 而不会先将 *l 重置为空切片。

func (*PropertyList) Save

func (l *PropertyList) Save() ([]Property, error)

Save 会将 l 的所有属性都保存为属性的切片。

type PropertyLoadSaver

type PropertyLoadSaver interface {
    Load([]Property) error
    Save() ([]Property, error)
}

PropertyLoadSaver 可以与属性切片相互转换。

type Query

type Query struct {
    // contains filtered or unexported fields
}

Query 表示数据存储区查询。

func NewQuery

func NewQuery(kind string) *Query

NewQuery 会为特定的实体种类创建一个新查询。

空种类意味着返回所有实体(包括由其他 App Engine 功能创建和管理的实体),称为不分类查询。 不分类查询不能包含针对属性值的过滤条件或排序顺序。

func (*Query) Ancestor

func (q *Query) Ancestor(ancestor *Key) *Query

Ancestor 会返回包含祖先过滤条件的衍生查询。 祖先不应该是 nil。

func (*Query) Count

func (q *Query) Count(c context.Context) (int, error)

Count 会返回查询的结果数量。

Count 发出的 API 调用的运行时间和数量与查询的偏移量和限制的总和成线性比例关系。 除非结果计数预计很小,否则最好指定一个限制;不然 Count 将继续运行,直到其完成计数或提供的上下文到期为止。

func (*Query) Distinct

func (q *Query) Distinct() *Query

Distinct 会返回一个衍生查询,该查询将根据投影字段集生成消除了重复的实体。 Distinct 仅用于投影查询。

func (*Query) End

func (q *Query) End(c Cursor) *Query

End 会返回具有给定端点的衍生查询。

func (*Query) EventualConsistency

func (q *Query) EventualConsistency() *Query

EventualConsistency 会返回一个衍生查询,此查询最终会返回一致的结果。 它只对祖先查询有影响。

func (*Query) Filter

func (q *Query) Filter(filterStr string, value interface{}) *Query

Filter 会返回一个衍生查询,其中包含基于字段的过滤条件。 filterStr 参数必须是字段名称,其后依次是可选空格以及运算符(>、<、>=、<= 或 = 中的一个)。 Filter 使用运算符将字段与提供的值进行比较。 多个过滤条件可通过 AND 运算符连接在一起。

func (*Query) GetAll

func (q *Query) GetAll(c context.Context, dst interface{}) ([]*Key, error)

GetAll 在给定的上下文中运行查询,同时返回与该查询匹配的所有键,并将值附加到 dst。

对于以下类型,dst 的类型必须为 *[]S、*[]*S 或 *[]P:某些结构体类型 S 或某些非接口非指针类型 P(使得 P 或 *P 可以实现 PropertyLoadSaver)。

特殊情况下,*PropertyList 是 dst 的无效类型,即使 PropertyList 是结构体的切片。 PropertyList 会被视为无效,以免在本应传递 *[]PropertyList 时被错误传递。

GetAll 返回的键与添加到 dst 中的实体是一一对应关系。

如果 q 是“仅限于键”查询,GetAll 会忽略 dst 并且仅返回键。

GetAll 发出的 API 调用的运行时间和数量与查询的偏移量和限制的总和成线性比例关系。 除非结果计数预计很小,否则最好指定一个限制;不然 GetAll 将继续运行,直到其收集完结果或提供的上下文到期为止。

func (*Query) KeysOnly

func (q *Query) KeysOnly() *Query

KeysOnly 会返回一个衍生查询,该查询仅生成键,而不是键和实体。 它不能与投影查询一起使用。

func (*Query) Limit

func (q *Query) Limit(limit int) *Query

限制会返回一个衍生查询,该查询对返回的结果数量设有限制。 负值意味着无限制。

func (*Query) Offset

func (q *Query) Offset(offset int) *Query

Offset 会返回一个衍生查询,该查询使用的偏移为返回结果之前要跳过的键数。 负值无效。

func (*Query) Order

func (q *Query) Order(fieldName string) *Query

Order 会返回一个衍生查询,该查询使用基于字段的排序顺序。 应用的顺序是添加字段的顺序。默认顺序是升序;要按照降序排序,请在 fieldName 前加上一个减号 (-) 作为前缀。

func (*Query) Project

func (q *Query) Project(fieldNames ...string) *Query

Project 会返回一个衍生查询,该查询仅生成给定字段。 它不能与 KeysOnly 一起使用。

func (*Query) Run

func (q *Query) Run(c context.Context) *Iterator

Run 会在给定上下文中运行查询。

func (*Query) Start

func (q *Query) Start(c Cursor) *Query

Start 会返回具有给定起点的衍生查询。

type TransactionOptions

type TransactionOptions struct {
    // XG is whether the transaction can cross multiple entity groups. In
    // comparison, a single group transaction is one where all datastore keys
    // used have the same root key. Note that cross group transactions do not
    // have the same behavior as single group transactions. In particular, it
    // is much more likely to see partially applied transactions in different
    // entity groups, in global queries.
    // It is valid to set XG to true even if the transaction is within a
    // single entity group.
    XG bool
    // Attempts controls the number of retries to perform when commits fail
    // due to a conflicting transaction. If omitted, it defaults to 3.
    Attempts int
}

TransactionOptions 是用于运行事务的选项。