我正在创建一个应用程序,用户可以在其中创建类别以将项目放入其中。这些项共享一些基本属性,但其余属性由它们所属的类别定义。问题是类别和它的特殊属性都是由用户创建的。
例如,用户可以创建两个类别:书籍和按钮。在这本书中'他可能会创建两个属性:页数和作者。在按钮类别中,他可以创建不同的属性:孔的数量和颜色。
最初,我将这些属性放在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。为了缩短这篇文章,我省略了一些关于我做了什么的细节,如果你需要知道我可能遗漏的东西,只需在评论中提出。
答案 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
上的函数才能从道具名称中清除属性值。