如何使用Expando查询事先未知的多个属性?

时间:2017-12-07 16:19:55

标签: python google-app-engine google-cloud-datastore app-engine-ndb

我正在创建一个应用程序,用户可以在其中创建类别以将项目放入其中。这些项共享一些基本属性,但其余属性由它们所属的类别定义。问题是类别和它的特殊属性都是由用户创建的。

例如,用户可以创建两个类别:书籍和按钮。在这本书中'他可能会创建两个属性:页数和作者。在按钮类别中,他可以创建不同的属性:孔的数量和颜色。

最初,我将这些属性放在Item中的JsonProperty中。虽然这有效,但这意味着我只是通过指定我要查找的类别来查询数据存储区,然后我必须在代码中过滤查询结果。例如,如果我要查找其作者为Carl Sagan的所有图书,我会查询Item类,其中包含category == books,并在结果中循环以仅保留与作者匹配的图书。

虽然我并不希望每个类别都有那么多项目(可能是数百种,不太可能达到一千种),但这看起来效率低下。所以我尝试使用ndb.Expando来制作索引的特殊属性 real 属性。我这样做了,在将项目放入数据存储区时为项添加了相应的特殊属性。因此,如果用户在“书籍”中创建了一个项目。类别和以前在该类别中创建的特殊属性' author',一个项目与特殊属性expando_author = author一起保存。它起到了我的预期,直到这一点(开发服务器)。

当我做一些查询时,真正的问题变得可见了。当他们在开发服务器中工作时,他们为每个特殊/ expando属性创建了复合索引,即使查询过滤器只是相等。虽然每个类别最多可以包含五个属性,但很明显它很容易失控。

示例查询:

items = Item.query()
for p in properties:
    items = items.filter(ndb.GenericProperty(p)==properties[p])
items.fetch()

现在,由于我事先并不知道属性是什么(虽然我会将其限制为5),但我无法在上传应用程序之前构建索引,即使我知道它可能意味着有更多我满意的索引。 Expando是我试图做的错误工具吗?我应该继续使用JsonProperty过滤代码中的结果吗?我非常感谢我能得到的任何建议。

PD。为了缩短这篇文章,我省略了一些关于我做了什么的细节,如果你需要知道我可能遗漏的东西,只需在评论中提出。

1 个答案:

答案 0 :(得分:2)

考虑将类别属性存储在前缀为类别属性名称的单个列表属性中。

喜欢(忘了我忘了确切的Python语法,切换到Go

class Item():
  props = StringListProperty()

book = Item(category='book', props=['title:Carl Sagan'])
button = Item(category='button', props=['wholes:5'])

然后你可以在category+props上有一个复合索引,并执行如下查询:

def filter_items(category, propName, propValue):
  Item.filter(Item.category == category).filter(Item.props==propName+':'+propValue)

您需要Item上的函数才能从道具名称中清除属性值。