如何在Google App Engine的字符串列表属性中查找键不在的对象

时间:2011-08-14 03:32:15

标签: python google-app-engine google-cloud-datastore

我很确定以上内容不是直接可行的(但我会很高兴出错)。所以这就是我想要做的,但我无法弄清楚如何使用有用的查询来工作。

class Challenge(db.Model):
    name = db.StringProperty()
    players = db.StringListProperty(default=[])
    created_on = db.DateTimeProperty(auto_now_add=True)
    completed_on = db.DateTimeProperty(default=None)

可能有成千上万的挑战。您可以随时加入任意数量的挑战(在“完成”之前,但您只能加入任何挑战。

编辑-----------------------------

挑战是异步完成的(它们可以持续多天),并且在那个时期结束时决定“胜利者”,因此人们可能同时面临几个挑战,等待这些挑战结束。基本上,您加入挑战并完成任务,然后等待其他人也这样做,然后在挑战结束时选择获胜者。在等待的同时,您可以加入并完成其他挑战。每次挑战限制为250-500人(尚未确定最高限额)

------------------------------修改

我想列出您可以加入的所有挑战,按created_on排序。 players是所有已加入挑战的人str(user.key())的列表。

你可以这样做:

already_in = Challenge.all().filter('players = ', str(self.user.key())).filter('completed_on =', None)
already_in_set = set()    
for challenge in already_in.fetch(1000):
    already_in_set.add(str(challenge.key()))  # Could cache this in the user object

challenges = Challenge.all().order('created_on')
keepers = []
for challenge in challenges:
    if str(challenge.key()) not in already_in_set:
        keepers.append(challenge)
        if len(keepers) > 11:
            break

现在keepers列出了你不在的列表。但上面的代码感觉不太理想。

当然还有另一种方法可以做到这一点。 (我不反对重构数据库以使其更好地工作)

我可以将already_in_set缓存为StringListPropery(indexed=False)对象User,这会提高速度,但是我必须修剪它以删除现在已完成的挑战(我可以在UI请求之外做。)

我希望我遗漏了一些关于如何使用AppEngine数据存储区进行查询的明显内容。

2 个答案:

答案 0 :(得分:3)

正如你猜测的那样,这是不可能的。列表属性中的元素是单独索引的,因此“不等于x”的过滤器将返回任何列表,其中至少有一个值不等于x,而不是所需的结果。

鉴于您描述的情况,用户似乎不太可能面临无限的挑战。获取他们已经存在的挑战,并从结果集中过滤掉这些结果,似乎是一个合理的解决方案。如果您想提高效率,可以针对用户存储挑战列表,反之亦然。这也意味着不再有多少用户可以参与特定挑战。

最后,请勿使用db.StringListProperty存储序列化密钥 - 而是使用db.ListProperty(db.Key)

答案 1 :(得分:0)

考虑到用户一次只能加入一个挑战的限制,如果您记录用户参与的未完成挑战(如果有),则可以非常有效地检索该挑战。然后(如果我理解正确的话)两个案例中的一个适用:用户正在参与挑战,在这种情况下,不需要查询Challenge,或者您需要查询可用的挑战。要执行后一个查询,还可以在挑战中存储completed标记。

这意味着,当挑战完成后,您将需要进行一些额外的簿记,找到所有参与的用户并排除他们的参与。