データストアのクエリ

PythonでのGQL

昨日はQueryクラスをインスタンス化してクエリを生成しました。クエリを生成するためのもう一つの方法がGQLです。GQLを使うとは次のような感じです。

query = db.GqlQuery('''
                SELECT * FROM Book
                ORDER BY %s %s
                ''' % (property, sort))


これは前にQueryクラスの例として上げたものとまったく同じ意味のGqlQueryクラスのインスタンスです。SQLに慣れている人は断然こっちですよね。・・・という私はSQLに慣れているわけではありませんけどね。

もう少し簡潔に書くことも出来ます。

query = Book.gql('''ORDER BY %s %s''' % (property, sort))


エンティティの種別 (クラス) が分かれば「SELECT * FROM 種別名 (クラス名) 」の部分は不要になりますからね。

上の例では「ORDER BY」しか使っていませんが、もちろん「WHERE」も使うことが出来ます。Queryクラスのフィルタに該当します。

結果の取得

上記はクエリを作ったに過ぎません。クエリは発行しないと結果を取得することが出来ません。クエリを発行して、結果を取得するためのメソッドはQuery/GqlQueryクラスのfetchメソッドがあります。・・・が、このメソッドちょっと使いにくい。なぜなら取得する件数の上限をかならず指定しないといけないからです。そして最大は1000件とのこと。1000件以上エンティティがある場合は、offsetを使って次の1000件を取得することになります。これってとてつもなく不便!

また、クエリの結果の数を取得するcountメソッドもやっかいです。なぜなら数を取得するだけでもクエリを全て発行する必要があるからです。数を取得するだけで全エンティティを取らないといけないなんてとっても非効率ですよね。

というわけで、私が落ち着いたのは以下の二つのメソッドを使うやり方です。

  1. Query/GqlQeuryのgetメソッドを使って結果が一件はあることを確認する
  2. その後イテレータを使って全ての結果を処理する


たとえばこんな感じ。

query = Player.all()
if query:
    for player in query:
        self.response.out.write(u'''
        <tr align=center>
            <td>%s</td>
            <td>%d</td>
            <td>%d</td>
            <td>%s</td>
        </tr>
        ''' % (player.name, player.level, player.score, player.charclass)
else:
    pass


全部で何件あるかはforループが回った回数で取得出来ます。

なお作りかけですが、この章用の簡単なサンプルを作りました。なくすと嫌なので公開しておきます。

サンプルコード置き場