2015年7月17日金曜日

GAE/P NDB のクエリで、2つの不等式を使う。

Google App Engine は、クエリの中で複数のプロパティに対して不等式を使うことが出来ません。
これ、結構不便です..

例えば、開始日と終了日の2つのプロパティに対して、
 開始日 < 7月10日 and 終了日 > 7月20日
と云うようなクエリは実行できないのです..

で、イロイロと調べて、こんな記事を見つけました。
http://stackoverflow.com/questions/22176586/optimizing-a-inequality-query-in-ndb-over-two-properties

クエリで1つ目の不等式を使い、iterで2つ目の不等式を使うのか。なるほど!!

続いて、こんな記事も見つけた。
http://ae-book.appspot.com/static/pgae-ndb-20121009.pdf

なるほど、iter で cursorも使えそうだな。

と、ここまでは良かったけど、どうも projection と cursor は一緒に使えないみたい..残念。

で、結論は、こんな感じに。

[モデル]
class Event(ndb.Expando):
 start_dt = ndb.DateProperty()  #開始日時
 end_dt = ndb.DateProperty()   #終了日時

[スクリプト]
next_curs = request.GET['curs']
cnt = 10
it = Event.query(Event.end_dt >= dt1).iter(projection=[Event.start_dt])
keys = []
if next_curs is not None:
 next_curs = int(next_curs)
 for e in it:
  if e.key.id() == next_curs:
   keys.append(e.key)
   break
next_curs = None
for e in it:
 if e.start_dt <= dt2:
  keys.append(e.key)
  if len(keys) >= cnt+1:
   next_curs = keys[cnt].id()
   keys.pop()
   break

主なポイントは、以下の通り。
 Event.query(Event.end_dt >= dt1) → 1つ目の不等式
 if e.key.id() == next_curs: → カーソル位置(キーID)まで早送り
 if e.start_dt <= dt2: → 2つ目の不等式
 if len(keys) >= cnt+1: → cnt件までループ