如何按可为空的重复字段排序ndb查询

1 投票
1 回答
1252 浏览
提问于 2025-04-18 12:32

我有一个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])

撰写回答