如何使用 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 选择器?

在 Django 模板中迭代 Expando 的动态属性

使用 expando 元类添加 curried 闭包作为静态属性会丢失默认参数值

如何让 ServiceStack 序列化/反序列化具有正确类型的 expando 对象

具有多个实体的命名查询并获取多个属性

Dart 的“Expando”功能是啥,它有啥作用?