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

How can I query for multiple properties not known in advance using Expando?

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

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

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

虽然我真的不希望每个类别有那么多项目(可能有数百个,不太可能达到一千个),但这看起来效率不高。所以我尝试用ndb.Expando让那些特殊的属性真正的属性被索引。我这样做了,在将项目放入 Datastore 时将相应的特殊属性添加到项目中。因此,如果用户在 'books' 类别中创建了一个项目,并且之前在该类别中创建了特殊的 属性 'author',则该项目将保存为特殊的 属性 expando_author = 里面的作者。直到此时(开发服务器)它都按我的预期工作。

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

示例查询:

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

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

PD。为了使这个 post 更短,我省略了一些关于我所做的事情的细节,如果你需要了解我可能遗漏的内容,请在评论中提问。

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

喜欢 (忘了我我忘记了确切的 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 上的一个函数来从 prop 名称中清除 属性 个值。