无效过滤器:每个查询只有一个属性可能包含不等过滤器(> =,< =,>,<)

时间:2013-12-13 14:17:03

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

我有许多可在某些时段预订的物品。例如。一个网球场。因此,每个项目都有许多相关的可用性槽,每个槽都由begintime和endtime定义。 Begintime和endtime被定义为datetime-objects,因此存储从09.00到11.30的可用性槽,例如。 2013-12-13 09.00(开始时间)至2013-12-13 11.30(结束时间)。

当预订请求进入时,我需要知道网球场是否适用于所需的时段。

所以我尝试根据开始时间和结束时间过滤可用性插槽,我的查询如下所示:

desired_availability_start = datetime(2013, 12, 13, 9,0,0)
desired_availability_end = datetime(2013, 12, 13, 10,0,0)
availability_slots = self.availability_slots.filter("begin <= ", desired_availability_start).filter("end >= ", desired_availability_end).fetch(limit=10)

但是我收到以下错误

invalid filter: Only one property per query may have inequality filters (>=, <=, >, <)

因为我试图过滤开始和结束属性。

根据输入以及主题Inequality Filter in AppEngine DatastoreBadFilterError: invalid filter: Only one property per query may have inequality filters (<=, >=, <, >)上的其他一些帖子,我目前的解决方案是首先过滤开始:

filtered_availability_slots = self.availability_slots.filter("begin <= ", desired_availability_start).fetch(limit=10)

然后过滤结束并将过滤后的项目附加到列表中:

final_availability_slots = []              
  for availability in filtered_availability_slots:         
      if availability.end >= desired_availability_end:  
        final_avaialability_slotes.append(availability)   

但这是实现我想要实现的目标的最佳方式吗?

我正在使用Google App Engine和Python

感谢任何帮助

感谢 托马斯

3 个答案:

答案 0 :(得分:2)

正如我猜您已经知道的那样,您不能使用多个数据存储区中的不等过滤器使用多个变量。除非您确实需要,否则您只能使用“开始”时间进行过滤,并且仍能获得非常准确的结果。

calitem = self.appointments.filter("begin >= ", start).filter("begin <= ", end).fetch(limit=10)

如果您真的需要,使用您的应用程序逻辑,您只能显示不超出“结束”值的项目。我没有看到任何其他方式。

答案 1 :(得分:1)

有点不清楚你在问什么。目前尚不清楚你是否理解这个问题:你试图使用两个不等式过滤器,而这是不允许的。做不到。

您必须解决此数据存储限制。

最基本的选择是自己暴力。使用一个过滤器,并自己手动过滤掉结果。过滤begin并对end进行排序可能有所帮助,但您必须完成搜索并选择所需的实际实体。

calitem = [x for x in self.appointments.filter("begin >= ", start).filter("begin <= " end) if x.end <= end]

在大多数情况下,您需要重新构建数据,以便不需要两个不等式过滤器。这可能是也可能是不可能的。

我正在猜测你正在做什么,但是如果你想根据他们的日历在上午11点看某人是否忙,那么这样做的方法是:

  1. 将时间缩短为时间段,而不是使用任意时间,即15分钟。
  2. 将事件存储为其使用的时间块列表。
  3. 查询包含上午11点的时间段的事件。

答案 2 :(得分:0)

我有类似的要求:从数据存储区中挑选出现在应该渲染/交付的实体。由于数据存储无法处理此问题,因此需要应用程序逻辑。我对满足约束两端的键进行了两次单独的查询,然后取出它们的交集:

satisfies "begin" criteria: k1, k3, |k4, k5|, k6
                            --------+------+----
satisfies "end" criteria:       k2, |k4, k5|, k7, k8

“开始”和“结束”的交集是键k4, k5

now = datetime.now()

start_dt_q = FooBar.all()
start_dt_q.filter('start_datetime <', now)
start_dt_q.filter('omit_from_feed =', False)
start_dt_keys = start_dt_q.fetch(None, keys_only=True)

end_dt_q = FooBar.all()
end_dt_q.filter('end_datetime >', now)
end_dt_q.filter('omit_from_feed =', False)
end_dt_keys = end_dt_q.fetch(None, keys_only=True)

# Get "intersection" of two queries; equivalent to
# single query with multiple criteria
valid_dt_keys = list(set(start_dt_keys) & set(end_dt_keys))

然后我迭代这些键获取我需要的实体:

for key in valid_dt_keys:
    foobar = FooBar.all().filter('__key__ =', key).get()
    ...

OR:

foobars = FooBar.all().filter('__key__ IN', valid_dt_keys)
for foobar in foobars:
    ...