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

谁说胖子不能爱 提交于 2019-12-22 12:26:26

问题


I have a number of items which are bookable in certain timeslots. Eg. a tennis court. So each item has got a number of associated availability slots each defined by begintime and endtime. Begintime and endtime are defined as datetime-objects so an availability slot from 09.00 - 11.30, is stored as eg. 2013-12-13 09.00 (begintime) to 2013-12-13 11.30 (endtime).

When a booking request comes in, I need to find out whether the tennis court is available for the desired timeslot.

So I am trying to filter availability slots based on start-time and end-time, and my query looks like this:

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)

but I get the following error

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

Because I am trying to filter on both the begin- and end-property.

Based on the input and from some of the other posts on the topic Inequality Filter in AppEngine Datastore and BadFilterError: invalid filter: Only one property per query may have inequality filters (<=, >=, <, >) my current solution is to first filter on begin:

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

and then filter on end and append the filtered items to a list:

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

But is this the best way of achieving what I want to achieve?

I am using Google App Engine and Python

Any help is appreciated

thanks Thomas


回答1:


It's a bit unclear what you're asking. It's not clear whether you understand the problem: You're trying to use two inequality filters, and it's simply not allowed. Can't do it.

You must work around this datastore limitation.

The most basic option is to brute force it yourself. Use one filter, and manually filter out the results yourself. It may help to filter on begin, and sort on end, but you'll have to go through the results and pick the actual entities you want.

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

In most cases, you'd want to restructure your data so that you don't need two inequality filters. This may or may not be possible.

I'm trying to guess at what you're doing, but if you're trying to see if someone is busy at 11am based on their calendar, a way to do this is:

  1. Break the day down into time periods instead of using arbitrary time, ie 15min blocks.
  2. Store an event as a list of the time blocks that it uses.
  3. Query for events that contain the time block for 11am.



回答2:


As I guess you already know, you can't use more than one variable with inequality filters using the datastore. Unless you really need, you can filter using the 'begin' time only, and still get pretty accurate results.

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

If you really need, using your application logic, you can only show the items that doesn't go beyond the 'end' value. I don't see any other way around.




回答3:


I have a similar requirement: pick entities out of Datastore that should be rendered/deliverd now. Since Datastore cannot handle this, application logic is required. I make two separate queries for keys that satisfy both ends of the constraint, and then take the intersection of them:

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

The intersection of "begin" and "end" are the keys 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))

I then iterate over those keys getting the entities I need:

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:
    ...


来源:https://stackoverflow.com/questions/20568673/invalid-filter-only-one-property-per-query-may-have-inequality-filters

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!