2 回答

TA贡献1824条经验 获得超6个赞
特别是对于前缀匹配,您可以在同一属性上使用多个不等式过滤器。即来自https://cloud.google.com/datastore/docs/concepts/queries “如果查询在给定属性上有多个不等式过滤器,则实体将匹配该查询,前提是该属性至少有一个单独的值满足所有过滤条件。”
该页面上的示例是SELECT * FROM Task WHERE tag > 'learn' AND tag < 'math'
. 或者对于你的情况query := datastore.NewQuery("Person").Filter("Name >= ", "Rob").Filter("Name <= Rob~").Order("Name")

TA贡献1850条经验 获得超11个赞
以下解决方案以编程方式解决了该问题。它是编码的,go但我相信它可以很容易地适应任何语言。
我将首先制作整个片段,然后将其分解。
func (store *PersonStore) Search(name string) ([]Person, error) {
context := context.Background()
persons := make([]*Person, 0)
query := datastore.NewQuery("Person").Filter("Name >= ", strings.ToLower(name)).Order("Name")
keys, err := store.client.GetAll(context, query, &persons)
if err != nil {
return nil, fmt.Errorf("unable to search for persons w/ names containing %s - %v", name, err)
}
filteredPersons := make([]*Perons, 0)
for i, p := range persons {
p.ID = keys[i].ID
if !strings.Contains(p.Name, strings.ToLower(name)) {
break
} else {
filteredPersons = append(filteredPersons, p)
}
}
}
1 - 小写假设
为了让这段代码工作,我们首先需要做出一个非常强的假设,即所有名称都是小写的。如果由于某种原因,您无法做出此假设,您仍然可以部分使用此代码,但效率会降低。
2 - 查询数据存储
代码的第一部分专门用于获取名称与所需模式匹配的 Persons 的数据存储区。
context := context.Background()
persons := make([]*Person, 0)
query := datastore.NewQuery("Person").Filter("Name >= ", strings.ToLower(name)).Order("Name")
keys, err := store.client.GetAll(context, query, &persons)
if err != nil {
return nil, fmt.Errorf("unable to search for persons w/ names containing %s - %v", name, err)
}
我们确保我们使用strings.ToLower(name)来确保我们不会获取ALL Person。理想情况下name也应该修剪,但这通常是在前端完成的,所以我们在这里省略了。
Name再一次,这是基于所有s 都是小写的假设。如果你不能假设这一点,你可以随时使用
query := datastore.NewQuery("Person").Filter("Name >= ", name).Order("Name")
你只会得到一个带有(可能很多)更多Person的初始列表。
最后,我们对获取的列表进行排序,.Order("Name")因为这将成为代码第二部分的基点。
3 - 过滤名称
到目前为止,它只是一段简单GetAll的代码。我们仍然需要将键插入到Person结构中。我们需要找到一种方法来优化它。为此,我们可以基于这样一个事实,即persons和keyslist 的长度和顺序是准确的。因此,即将到来的for循环开始就像一个常规的将 Key 插入结构位一样。
for i, p := range persons {
p.ID = keys[i].ID
下一点是优化的地方:因为我们知道Persons 是由 排序的,所以Name我们确定,只要strings.Contains(p.Name, strings.ToLower(name))不是真的,我们就选择了所有符合我们标准Person的 s Name,也就是说,只要p.Name不是以Rob不再有,但有Roc或Rod或任何在字典上大于此的东西。
if !strings.Contains(p.Name, strings.ToLower(name)) {
break
然后我们可以使用break指令来逃避我们的循环,希望只解析persons列表中符合我们标准的前几个元素。这些属于else声明:
} else {
filteredPersons = append(filteredPersons, p)
}
4 - 在没有小写假设的情况下过滤名称
正如我之前所说,如果你不能假设所有的名字都是小写的,你仍然可以使用这个代码,但它不会被优化,因为你必须扫描persons查询返回的完整列表。
代码应该看起来像这样
filteredPersons := make([]*Perons, 0)
for i, p := range persons {
p.ID = keys[i].ID
if strings.Contains(p.Name, strings.ToLower(name)) {
filteredPersons = append(filteredPersons, p)
}
}
- 2 回答
- 0 关注
- 119 浏览
添加回答
举报