如何按可为空的重复字段排序ndb查询
我有一个ndb模型,其中有一个重复的属性:
class MyModel(ndb.Model):
foo = ndb.KeyProperty(repeated=True)
我想对foo
进行不等式过滤,这意味着我需要按foo
进行排序:
query = MyModel.query()
query = query.filter(MyModel.foo != my_key)
# I don't actually care about doing this, but I have to because of the inequality filter.
query = query.order(MyModel.foo)
我希望查询能包含那些foo
为空的实体。如果我在foo
里放一个虚拟字段,这样是可以的:
def _pre_put_hook(self):
if not self.foo:
self.foo.append(ndb.Key('Dummy Kind', 'Dummy ID'))
但这样做似乎不太干净。有没有更好的方法呢?
1 个回答
5
当Datastore在索引中存储带有 repeated=True
的属性时,它会为每个值存储一行数据。简单来说,如果你有一个空的重复属性,它就不会出现在你的EntitiesByProperty索引中。这意味着你无法查询到一个空的重复属性。
有几种解决方案,但每种都有自己的利弊:
添加一个虚拟值。
你提到的方法的好处是,你现有的查询可以得到你想要的结果。不过,当你想添加真实数据时,你需要处理这个虚拟值的清理工作。
使用 ComputedProperty
。
你可以为foo属性的大小添加一个新属性:
class MyModel(ndb.Model):
foo = ndb.KeyProperty(repeated=True)
foo_len = ndb.ComputedProperty(lambda self: len(self.foo))
但是,要获取那些foo
值不匹配my_key
或为空的实体,你需要写两个查询才能得到结果:
ndb.gql("SELECT * FROM MyModel WHERE foo != :1", my_key)
ndb.gql("SELECT * FROM MyModel WHERE foo_len == :1" 0)
注意,如果foo
不是重复的,使用以下查询就能得到你想要的结果:
ndb.gql("SELECT * FROM MyModel WHERE foo != :1", my_key)
即使没有空列表的情况,使用重复属性时也需要小心。特别是,只有一个重复属性需要匹配你的键。因此,下面定义的模型仍然会匹配你的查询,因为my_key2 != my_key
:
MyModel(foo=[my_key, my_key2])