祖先查询直系后裔 - 谷歌数据存储 [英] Ancestor Query Direct Descendants - Google Datastore

查看:154
本文介绍了祖先查询直系后裔 - 谷歌数据存储的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用Go和Google Datastore在Google App Engine中构建目录应用程序。我使用数据库的 Ancestor 功能来管理不同的产品类别。以下是一些数据的例子:

乐器 - >吉他 - >吉布森 - > Les Paul



乐器 - >吉他 - >挡泥板 - > Stratocaster



乐器 - >低音吉他 - >音乐人 - > Stingray



乐器是根音实体。当我点击它时,我希望看到吉他 Bass Guitars ,但是我看到的是所有的后裔乐器直到最后一个实体。这不是我要找的。我只对乐器的直接后裔感兴趣。

有些帖子,像这样,建议在数据存储中创建一个字段来跟踪直接父母。但是,如果我要手动跟踪父实体,为什么要使用 Ancestor 功能呢?它会比筛选匹配直接父字段的查询更快吗?



以下是获取类别的方法:

  func(cat * Category)GetCategories(r * http.Request,pk string)([] CategoryReturn,error){
//获取上下文
c:= appengine .NewContext(r)

var q * datastore.Query
var err error

//获取父键
k,err:= datastore.DecodeKey (pk)

if err!= nil {
//处理错误
return [] CategoryReturn {},err
}

q = datastore.NewQuery(Category)。Ancestor(k)

//填充类别切片
var categories [] CategoryReturn
keys,err:= q.GetAll(c ,&类别)

if err!= nil {
//处理错误
return [] CategoryReturn {},err
}

//创建返回对象
results:= make([] CategoryReturn,0,20)

for i,r:= range categories {
k:= keys [i ]
y:= CategoryReturn {
名称:r。 Name,
Id:k.IntID(),
Key:k.Encode(),
}

results = append(results,y)
}

返回结果,无

}


您需要考虑应用程序中需要强一致性的任何部分,然后考虑实体&实体组将需要参与相应的查询和交易(您现在可以在跨组交易中拥有多达25个),但以这种方式使用祖先会为我敲响警钟。



通过将它们视为逻辑构建数据模型的一种方式,实体组很容易被抓住(我有!),但这可能会导致出现问题,最终导致写入争用在一个不必要的大型实体小组上。



相反,最好考虑应用程序中需要强大一致性的点,并围绕它设计实体组。



在这种情况下,我可能只需要一个 parentCategory 属性(类型为 datastore.Key )。您可以像这样查询乐器的子类别:

  k:= datastore.NewKey( c,Category,Musical Instruments,0,nil)
q:= datastore.NewQuery(Category)。Filter(parentCategory =,k)

(我对Go比较陌生,所以上面可能是一个近似值)

假设在每个类别中都有某种 Product ,并且要查询所有 Product 可以在树中的任何级别(例如 Telecaster guitars Minimoog)中的给定 Category 乐器 那么你可能需要一个多值属性(在Go中我猜这可能是一个 []数据存储.Key

I'm building a catalog application in Google App Engine, using Go, and Google Datastore. I'm using the Ancestor features of the datatore to manage different product categories. Here's an example of some data:

Musical Instruments -> Guitars -> Gibson -> Les Paul

Musical Instruments -> Guitars -> Fender -> Stratocaster

Musical Instruments -> Bass Guitars -> Music Man -> Stingray

Musical Instruments is the root entity. When I click it, I expect to see Guitars and Bass Guitars, but instead I see everything that is a descendant of Musical Instruments all the way to the last entity. Which is not what I'm looking for. I'm only interested in the direct descendants of Musical instruments at this point.

Some posts, like this one, suggest creating a field in the datastore to track direct parents. But, if I'm going to track parent entities manually, why use the Ancestor features at all? Would it be faster than filtering queries who match a direct parent field?

Here's the method for getting categories:

func (cat *Category) GetCategories(r *http.Request, pk string) ([]CategoryReturn, error) {
//get context
c := appengine.NewContext(r)

var q *datastore.Query
var err error

//get parent key
k, err := datastore.DecodeKey(pk)

if err != nil {
    //handle error
    return []CategoryReturn{}, err
}

q = datastore.NewQuery("Category").Ancestor(k)

//populate category slices
var categories []CategoryReturn
keys, err := q.GetAll(c, &categories)

if err != nil {
    //handle error
    return []CategoryReturn{}, err
}

//create return object
results := make([]CategoryReturn, 0, 20)

for i, r := range categories {
    k := keys[i]
    y := CategoryReturn {
        Name: r.Name,
        Id: k.IntID(),
        Key: k.Encode(),
    }

    results = append(results, y)
}

return results, nil

}

解决方案

You will need to think about any parts of your application that do need strong consistency and then consider what entities & entity groups will need to participate in the corresponding queries and transactions (you can now have up to 25 in a cross-group transaction), but your use of ancestors in this way rings alarm bells for me.

It's easy to get caught out (I have!) with entity groups by thinking of them as a way to logically structure your data model, but this can cause problems down the line where you end up with write contention on an unnecessarily large entity group.

Instead, it's best to think about the points in your application where you need strong consistency and design your entity groups around that.

In this scenario I would probably just have a parentCategory property (of type datastore.Key). You can then query for subcategories of Musical Instruments like this:

k := datastore.NewKey(c, "Category", "Musical Instruments", 0, nil)
q := datastore.NewQuery("Category").Filter("parentCategory =", k)

(I'm quite new to Go so the above might be an approximation)

Assuming within each category you have some kind of Product and you want to query for all Products within a given Category at any level in the tree (e.g., Telecaster in Guitars, or Minimoog in Musical Instruments then you will probably need a multi-value property (in Go I guess this would probably be a []datastore.Key slice) representing the branch of the Category tree.

这篇关于祖先查询直系后裔 - 谷歌数据存储的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆