【问题标题】:invalid filter: Only one property per query may have inequality filters (>=, <=, >, <)过滤器无效:每个查询只有一个属性可能有不等式过滤器(>=、<=、>、<)
【发布时间】:2014-01-01 08:24:00
【问题描述】:

我有一些可以在特定时间段预订的项目。例如。一个网球场。因此,每个项目都有许多相关的可用性时段,每个时段由 begintime 和 endtime 定义。开始时间和结束时间被定义为日期时间对象,因此从 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 (>=, <=, >, <)

因为我试图过滤 begin- 和 end- 属性。

根据输入和关于主题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

感谢任何帮助

谢谢 托马斯

【问题讨论】:

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


【解决方案1】:

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

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()
    ...

或者:

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

【讨论】:

    【解决方案2】:

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

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

    最基本的选择是自己暴力破解。使用一个过滤器,然后自己手动过滤掉结果。过滤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 点时间段的事件。

    【讨论】:

    • 我已经更新了我的问题,使其更加精确并包含解决方案。但我不知道是否有更好的方法来实现我想要实现的目标。使用常规 SQL 语法,我可以在一个查询中轻松实现,但我不知道如何使用 Google App Engine
    • 正如我所提到的,答案是,你不能。至少,不是单个查询。你所做的本质上是正确的。
    【解决方案3】:

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

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

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

    【讨论】:

    • 我更新了我的问题,包括一个有效的实现,在数据存储和我的应用程序逻辑之间拆分过滤。但如果可能的话,我更喜欢使用数据存储的解决方案
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-21
    • 1970-01-01
    • 1970-01-01
    • 2022-11-10
    相关资源
    最近更新 更多