如何使用 Expando 查询预先不知道的多个属性?
Posted
技术标签:
【中文标题】如何使用 Expando 查询预先不知道的多个属性?【英文标题】:How can I query for multiple properties not known in advance using Expando? 【发布时间】:2017-12-07 16:19:54 【问题描述】:我正在制作一个应用程序,用户可以在其中创建类别以将项目放入其中。这些项目共享一些基本属性,但其余的由它们所属的类别定义。问题是类别及其特殊属性都是由用户创建的。
例如,用户可以创建两个类别:书籍和按钮。在“书”类别中,他可以创建两个属性:页数和作者。在按钮类别中,他可能会创建不同的属性:孔数和颜色。
最初,我将这些属性放在 Item 内的 JsonProperty 中。虽然这可行,但这意味着我只需通过指定我要查找的类别来查询数据存储区,然后我必须在代码中过滤查询结果。例如,如果我要查找作者为 Carl Sagan 的所有书籍,我将使用 category == 书籍查询 Item 类,并循环遍历结果以仅保留与作者匹配的书籍。
虽然我真的不希望每个类别有那么多项目(可能有数百个,不太可能达到一千个),但这看起来效率低下。所以我尝试使用 ndb.Expando 来制作那些被索引的特殊属性 real 属性。我这样做了,将相应的特殊属性添加到项目时将其放入数据存储区。因此,如果用户在“书籍”类别中创建了一个项目,并且之前在该类别中创建了特殊属性“作者”,则将保存一个项目,其中包含特殊属性 expando_author = author。在此之前它按我的预期工作(开发服务器)。
当我进行一些查询时,真正的问题变得显而易见。当他们在开发服务器中工作时,他们为每个特殊/扩展属性创建了复合索引,即使查询过滤器只是相等的。虽然每个类别最多可以有五个属性,但很明显它很容易失控。
查询示例:
items = Item.query()
for p in properties:
items = items.filter(ndb.GenericProperty(p)==properties[p])
items.fetch()
现在,由于我事先不知道属性是什么(尽管我将其限制为 5 个),所以我无法在上传应用程序之前构建索引,即使我知道这可能意味着拥有更多我喜欢的索引。 Expando 是我正在尝试做的错误工具吗?我应该继续使用 JsonProperty 过滤代码中的结果吗?如果能得到任何建议,我将不胜感激。
PD。为了使这篇文章更短,我省略了一些关于我所做的细节,如果您需要知道我可能遗漏的内容,请在 cmets 中询问。
【问题讨论】:
【参考方案1】:考虑将类别的属性存储在以类别属性名称为前缀的单个列表属性中。
喜欢(忘了我,我忘了确切的 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
上使用一个函数来从道具名称中清除属性值。
【讨论】:
你的想法听起来很不错,我会用它做一个例子并用结果来回应。 非常感谢,它按预期工作。我现在将使用更大的数据集对其进行测试,但这绝对是要走的路。再次感谢!以上是关于如何使用 Expando 查询预先不知道的多个属性?的主要内容,如果未能解决你的问题,请参考以下文章
是否有跨浏览器的方式在 expando 属性上使用 jQuery 选择器?
使用 expando 元类添加 curried 闭包作为静态属性会丢失默认参数值