blogSetomits

Hello

Google App Engine で db から ndb に移行したときのメモ

Google App Engine ではデータの保存には Datastore というオブジェクトデータベース的なものを使います。プログラムから Datastore にアクセスして値を保存したり取り出したりするために db というモジュールが用意されていて、

from google.appengine.ext import db

class Entry(db.Model):
author_id = db.IntegerProperty()
body = db.StringProperty(multiline = True)

といった具合に使います。

一方で、去年の5月くらいから、より高機能な Datastore アクセスモジュールとして ndb というのが用意されていました。そちらを使うとメモリ上に Datastore から取り出したオブジェクトのキャッシュがされたりします。

今年の2月にリリースした家族フォトでもバックエンドやウェブ版では Google App Engine を使っているのですが、開発を始めた当初は「なんとなく今までにやったことがあること」ということで db を使ってしまっていたのですが、リリース前に思い立って db から ndb に移行しました。ちょっと忘れていることもありますが、その際のメモを書いておこうかと思います。
とは言え、実はNDB Cheat Sheetというのがあって、そちらを見ながらやっていけばおおよそ問題無いかと思います。チートシートにも書かれているのですが、 db から ndb に変更するにあたって、すでに保存されているデータ自体のマイグレーションなどは必要ありません。

また、 General differences に書かれている db と ndb の一般的な違いについてもざっくりと訳すと

  • ndb は型に厳格。例えば db ではキーが求められる場合にエンティティ自体か文字列を渡すこともできましたが、 ndb では絶対にキーを渡さないといけません。

  • ndb はリストに厳格。例えば db では db.put() に対してエンティティ、またはエンティティのリストを渡すことができました。 ndb ではひとつのエンティティを渡すときには entity.put() を使い、複数のエンティティを渡すときには ndb.put_multi()を使います。

  • ndb では関数よりメソッドが好ましいです。 db では db.get(key) や db.put(entity) とするのに対して ndb では key.get() や entity.put() とします。

  • ndb では全く同じことをするのに2つの API を用意することを嫌います。(その一方でわずかに違うことをするためには2つの API が用意されていたりします)

ということです。



ということで、細かく用意されている表を見ながら db を使っているコードを変更していきます。僕は印刷して赤ペンでチェックしながら変更していきました。

前述しましたが、 Model の作り方・エンティティ自体について・データの取り出し・データの保存・データの削除・プロパティの型・キーの作成・キーの操作・トランザクション・クエリー・カーソルと順に直していくと良いともいます。

ちなみに僕のケースでは、以下の変更が多かったです。

  • エンティティのキーを取得するのに db では entity.key() とメソッド呼び出しだった箇所が ndb では entity.key とプロパティアクセスになっている

  • エンティティの削除をするのに、 db では model_instance.delete() とオブジェクト自体を削除するような操作だったのが ndb では model_instance.key.delete() とキーを削除する操作になった。

  • 文字列を保存するプロパティである db.StringProperty() に改行を含めたい場合は db では multiline=True を指定しておく必要があったが、 ndb では常に改行を含むことができるようになった。

  • キーから数値の ID を取得するのに db では key.id() としていた箇所が ndb では key.integer_id() とするようになった。

  • キーを文字列化するのに db では str(key) でいけたが ndb では key.urlsafe() とするようになった。

  • クエリー周りはもろもろ変更。






僕のケースでは最初に db でコードを書いていて後で ndb に変えたのですが、その際に unittest を用意していたことが大分助けになりました。移行を考えている人はまずは db の時点でちゃんと通るようにテストを作っておくことが重要だと思います。

ただ、実は db を ndb に変えると、単にそれだけでテストがうまく実行できなくて困りました。要は ndb にはキャッシュの機構が備わっているので、 testbed で memcache スタブが使えるようにしておいてあげなくてはいけなかったのでした。

class TestEntry(unittest.TestCase):
def setUp(self):
self.testbed = testbed.Testbed()
self.testbed.activate()
self.testbed.init_datastore_v3_stub()
self.testbed.init_memcache_stub() # ← ここ
Posted at 23:56 by setomits Comments : 0