(初心者)Google App EngineのDatastoreの基本的な使い方

# 前提

```from google.appengine.ext import db``` を使った方法。(ndbではなくdbのほう)
GAE (Google App Engine) ※GCEでも同じだと思うけど使ったこと無い
Python2.7

# Cloud ConsoleからのDatastore操作

## 言葉の意味

エンティティは、RDBMSで言うとレコードに相当。表で言うと行に相当。
種類は、RDBMSで言うと表に相当。
キー識別子は、RDBMSで言うとPrimary Key。
名前空間は不明。

## エンティティの作成

データストア画面の上部にある「エンティティを作成」から作成画面に遷移する。

- 名前空間：[デフォルト]
- 種類：UserData
- キー識別子：カスタム名：xxxxxxxxxxxxxxxxx(lineId)

以下は「プロパティを追加」を選択して追加。

lineIdの例：

- 名前：lineId
- タイプ：文字列
- 値：xxxxxxxxxxxxxxxxx(lineId)

追加したプロパティの一覧。

- lineId：xxxxxxxxxxxxxxxxx(lineId)
- dashId：shoshuriki
- message：誰かがあなたを呼んでいます
- registrationTime：2016/01/02 00:27:12

※「インデックス登録」はよくわからないが、登録したほうが検索性能が上がりそうなのでチェックを入れておく。トレードオフは不明。（インサートが遅くなる？？）

## エンティティの参照と更新 

「名前/ID」を選択すれば更新画面に遷移する。ここで値なども確認可能。

- 名前空間、種類、キー(キー識別子)、これらは更新(変更)不可。
- プロパティは更新可能。(名前、タイプ、値、これらはいずれも更新可能。)
- 「保存」を選択すればデータストアに保存される。

## エンティティの削除

「名前/ID」の左隣にあるチェックボックスで選択し、
「エンティティを作成」の右側にある「削除」から削除可能。

## エンティティの検索

種類のドロップダウンリストを選択したり、
「エンティティをフィルタ」から条件を設定して
表示するエンティティを絞り込むことが可能。


# App EngineからのDatastore操作

【2017/1/4追記 ここから】
App EngineからDatastoreを操作する方法には2種類ある。

- db (from google.appengine.ext import db)
- ndb (from google.appengine.ext import ndb)

どちらもDatastoreを操作できることには違いが無いが、ndbのほうが新しいモジュールなので、これから始める場合はndbが推奨のようである。
何らかの理由があってdbモジュールを使わないといけない場合は、本記事を参考にして頂けると幸いである。

ndbとは
https://cloud.google.com/appengine/docs/python/ndb/?hl=ja
dbからndbの移行について
https://cloud.google.com/appengine/docs/python/ndb/db_to_ndb?hl=ja
【2017/1/4追記 ここまで】


以下のページを参考。
https://cloud.google.com/appengine/docs/python/datastore/entities


## エンティティの作成

エンティティを作成する前に、元になるクラスを作成する。

```
from google.appengine.ext import db

class UserData(db.Model):
  lineId = db.StringProperty()
  dashId = db.StringProperty()
  message = db.StringProperty()
  registrationTime = db.StringProperty()
```

これを元にインスタンスを作成し、Datastoreにputすることでエンティティとして作成される。

```
userData = UserData(
  key_name = 'xxxxx(lineId)',
  lineId = 'xxxxx(lineId)',
  dashId = 'shoshuriki',
  message = u'誰かがあなたを呼んでいます',
  registrationTime = '2016/01/02 00:27:12',
)
userData.put()
```

Cloud Platformで設定した項目を比べてみると以下になる。

- 種類：UserData (クラス名がそのまま種類(kind)になる。指定したい場合はメンバ関数kindを追加して文字列を返せばそれが種類になる(未確認))
- キー識別子：key_nameに代入される文字列
- 名前空間：未指定 (どこで指定するのか不明)

## エンティティの参照と更新

キー識別子が分かっている場合にのみ有効な方法。
キー識別子からエンティティのキーオブジェクトを取得し、キーオブジェクトからエンティティを取得する。
エンティティは自分で作成したクラスなので、自由にプロパティに参照・書き込みが可能。
書き込みした場合は、最後にputすることでDatastoreにエンティティを送信する。

```
try:
  key = db.Key.from_path('UserData', 'xxxxx(lineId)')
  userData = db.get(key)
  old_message = userData.message # 参照部分
  userData.message = u'ゆっくり来てください' # 更新部分
  userData.put() # もし参照のみならputは不要
except:
  print(u'見つかりませんでした')
```

※対象が見つからないと例外が発生するのでtryブロックが必要。

## エンティティの削除

キー識別子が分かっている場合にのみ有効な方法。
キー識別子からエンティティのキーオブジェクトを取得し、エンティティを削除する。

```
try:
  key = db.Key.from_path('UserData', 'xxxxx(lineId)')
  db.delete(key)
except:
  print(u'見つかりませんでした')
```

※対象が見つからないと例外が発生するのでtryブロックが必要。

## エンティティの検索

1つの種類に対し、プロパティの値を使って絞り込み、結果を得る。
対象となるエンティティが1つの場合はlimit=1を指定しておくと安心。

```
try:
  q = UserData.all()
  q.filter('dashId = ', 'shoshuriki')
  for p in q.run(limit=1):
    lineId = p.lineId # dashIdからlineIdを逆引き
except:
  print(u'見つかりませんでした')
```

※対象が見つからないと例外が発生するのでtryブロックが必要。
※dashIdからkey_nameを逆引きする方法は？

# 参考

Google Cloud Platform - データストア
https://console.cloud.google.com/datastore

DB to NDB Client Library Migration (端的に使い方がまとまっているので判りやすい)
https://cloud.google.com/appengine/docs/python/ndb/db_to_ndb?hl=ja