GAEのクエリクラスでのfetch()

いわゆる limit, offset の指定でちょっと詰まった→とりあえず解決した、のでメモ。

テストデータが100件入っているとする。うち、50件は「sale_price = 100」にマッチする、とする。

class Song(db.Model):
    title = db.StringProperty()
    composer = db.StringProperty()
    date = db.DateTimeProperty()
    sale_price = db.IntegerProperty()

# test:1
song = Song.all().fetch(limit=3, offset=0)
print len(song)    # 結果 3

# test:2
song = Song.all()
song.fetch(limit=3, offset=0)
print len(song)    # 結果 100

# test:3
song = Song.all()
song_data = song.fetch(limit=3, offset=0)
print len(song_data)    # 結果 3

# test:4
song = Song.all().filter('safe_price = ', 100).fetch(limit=3, offset=0)
print len(song)    # 結果 3

# test:5
song = Song.all().filter('safe_price = ', 100)
song.fetch(limit=3, offset=0)
print len(song)    # 結果 50

# test:6
song = Song.all().filter('safe_price = ', 100)
song_data = song.fetch(limit=3, offset=0)
print len(song_data)    # 結果 3

ん?filter() と同じノリで書いてたら希望する結果が返ってこない。ドキュメントにある「データストアそのものによってスキップされません。」のことかしら?

limit および offset 引数はそれぞれ、データストアからフェッチする結果の数と fetch() メソッドによって返される結果の数をコントロールします。

    * データストアが offset +limit の結果をフェッチし、アプリケーションに渡します。最初の offset 結果は、データストアそのものによってスキップ されません。
    * fetch() メソッドが最初の offset 結果をスキップし、残り(limit 結果)を返します。
    * クエリの性能特性は、offset 数 + limit と直線的に比例します。

上のコードだと、テストの 1,3,4,6 はこういう動作をしている。

  1. song に入る値(データストアから帰ってくる値)は、3件(limit)+0件(offset) → 3件。
  2. fetch() メソッドが 0件(offset) をスキップして 3件(limit) のデータを song_data へ入れている。
  3. 結果、件数を表示すると3件になる。

テストの 2,5 はこういう動作をしている。

  1. song に入る値(データストアから帰ってくる値)は、3件(limit)+0件(offset) → 3件。
  2. song に入っている件数を表示していることになるので、データストアからから取得された件数(100件, 50件)が表示される。

なので、こうなる。

# test:7
song = Song.all()
print len(song.fetch(limit=3, offset=0))   # 結果 3

理解はこれであってるかな(・∀・)わーい

補足

fetch() で帰ってくるデータは List型でした。

# test:1
song = Song.all().fetch(limit=3, offset=0)
print len(song)    # 結果 3
print type(song)   # <type 'list'>