NamespaceごとにDatastoreを複製した
GCPのDatastoreにはnamespaceによってパーティションを作る機能があります。一つのnamespaceにあるものを丸ごと違うnamespaceに移す、というのはどのようにやればいいのか。やることがあったので書いておきます。
Namespaceを切り替えることはできない?
そもそも最初にやりたかったのは、datastoreに保存された全てのEntityのnamespaceを変更できないかということ。
ただ、どうやらできない?
Namespace is the part of the Key. So you can't change or copy all data from one namespace to another. As I understand all you can do is to fetch all objects from one namespace and create NEW objects with the same properties in another namespace.
というわけで、デフォルトのnamespaceから新しくnamespaceを切って丸ごとコピーする方法をやってみました。
namespace_manager
namespaceを変えるには、namespace_managerを使います。
import logging
from google.appengine.api import namespace_manager
#現在のnamespaceを知るには
current_namespace = namespace_manager.get_namespace()
# defaultは空
logging.debug(current_namespace)
# namespaceをnew_namespaceに設定
namespace_manager.set_namespace('new_namespace')
# 以下でput()したら設定したnamespaceで保存される
保存したいもエンテティはこんな形式だと仮定します。idはitemをそのまま使うということにしておきます。
class Item(ndb.Model, NDBMixin):
item = ndb.StringProperty()
message = ndb.StringProperty()
namespaceを変更した場所に丸ごと保存するには?
前のnamespaceの状態で、datastoreから引き出してきて、set_namespaceしたあとに保存します。
# 全件取得
items = Item.query().fetch()
# namespaceを変更
namespace_manager.set_namespace('new_namespace')
entities = (Category(
id=item.item,
item=item.item,
message=item.message,
) for item in items)
# 一括保存
ndb.put_multi(entities)
parentキーも保存する場合
複数のカインド含めて丸ごと複製したいときに、parentキーを持っていたりすることもあります。その際には、もちろんですがキーリファレンスも作り直して保存してあげる必要があります。
class ChildItem(ndb.Model, NDBMixin):
item = ndb.StringProperty()
children = ChildItem.query().fetch()
entities = (ChildItem(
id=child.item,
parent=ndb.Key(Item, item.key.parent().get().item),
item=child.item,
) for child in children)
ndb.put_multi(entities)
こんな感じでやってみましたが、他にいい方法がありそうな気もします。。