はじめに
Cloud FirestoreはFirebaseの機能の1つです。今までUnityにはSdkが配布されておらず、RealtimeDatabaseの方(こちらにはSdkが配布されていたため)を利用するケースが多かったと思われます。しかし、知らぬ間に__FirestoreのSdkも配布を開始__していました。
とはいえ、だいぶ新しい(2020年に出たっぽい?)こともありUnity(C#)に関しては情報が少ないため、Firebaseなんもわからんな身ながら使い方を備忘録として残しておこうと思います。
ちなみにUnityに限らなければ他の記事でも十分紹介されていると思うので、Firestore自体の構造の説明などは基本省いています(書くのがめんどくさいわけじゃないですよ…?)。
情報の書き込み
まずは情報の書き込み方法です。一番簡易的なものは以下の通り。
// id未指定(自動で生成されます)
Task writeTask = dataBase.Collection(path).Document().SetAsync(data);
// id指定
Task writeTask = dataBase.Collection(path).Document(id).SetAsync(data);
data
はDictionary<string, object>
のもの。ちゃんと終了したのかなどをしっかり確認する場合は上記のようにTaskとして変数に保存して、task.IsCompleted
がtrue
なるまでコルーチンで待機させたり、~.SetAsync(data).ContinueWith()
(task.ContinueWith()
でも可)などで対応してあげましょう。
以下は書き込む内容の例。書き込むデータはDictionary<string, object>
です。Keyの方はそのままデータベース上のキーになります。大文字、小文字でも異なるので注意しましょう。
Dictionary<string, object> data = new Dictionary<string, object>()
{
{"Name", "Hoge"},
{"Point", 1},
{"IsCompleted", true},
};
情報の読み込み
全データ取得
以下のコードはid
と等しいId
のドキュメントにおけるPointフィールドの値を取得してログ出力しているものです。
// dataBase = FirebaseFirestore.DefaultInstance;
public async void ReadPointAsync(string id)
{
int point = 0;
Query query = dataBase.Collection(userDataPath);
QuerySnapshot querySnapshot = await query.GetSnapshotAsync();
foreach (DocumentSnapshot document in querySnapshot.Documents)
{
if (document.Id.Equals(id))
{
Debug.Log($"Hit user data.(Id:{document.Id})");
Dictionary<string, object> docDictionary = document.ToDictionary();
if (docDictionary.ContainsKey("point"))
{
Debug.Log($"Point:{docDictionary["point"]}");
}
break;
}
}
}
上のスクリーンショットのようなドキュメントがあるとしたら、(Idは等しかったとして)Point:0
というログ出力が得られるはずです。
dataBase
はFirebaseFirestore.DefaultInstance
です。
userDataPath
はスペルミス防止かつ何度も文字列打つのだるいので、あらかじめ記載コード外の部分で宣言してあるコレクションのパス(今回の例で言うと値はUserData
)です。なんなら"point"
とかも全部似たような感じであらかじめ宣言してあるんですが、あんまり事前にメソッド外で宣言した変数ばっかになると備忘録の際はわかりにくいかなと思ったので、今回は直に記述し直しました。
結果を返すメソッドにする
先ほどのはvoid
なので、取得したデータを返したりはしていませんでした。もちろん、先ほどのメソッド内でデータセットを行うこともできますが、一応他のクラスから使用する場合なども考えて、結果を返すメソッドにしてみます。
public async Task<int> ReadPointAsync(string id)
{
int point = 0;
Query query = dataBase.Collection(userDataPath);
QuerySnapshot querySnapshot = await query.GetSnapshotAsync();
foreach (DocumentSnapshot document in querySnapshot.Documents)
{
if (document.Id.Equals(id))
{
Debug.Log($"Hit user data.(Id:{document.Id})");
Dictionary<string, object> docDictionary = document.ToDictionary();
if (docDictionary.ContainsKey("point"))
{
Debug.Log($"Point:{docDictionary["point"]}");
point = (int) Convert.ChangeType(docDictionary["point"], typeof(int));
}
break;
}
}
return point;
}
まあ、ほとんど変わらないんですけど…、使用例は以下の通り。
IEnumerator loadingData()
{
Task<List<int>> task = firebaseController.ReadPointAsync();
while (!task.IsCompleted)
{
yield return null;
}
point = task.Result;
}
StartCoroutine(loadingData());
もしくは、以下のようにContinueWith()を使うこともできます。
firebaseController.ReadPointAsync().ContinueWith(task => { point = task.Result; });
得た情報のCast
stringなら、name = dictionary["path"].ToString();
などで問題ありませんが、そのほかの型の場合はダウンキャストになり色々めんどくさいです。SystemのConvert.ChangeType()
を用いるのが楽です。
// need "using System;"
Dictionary<string, object> dictionary = (Dictionary<string, object>) Convert.ChangeType(
docDictionary["path"],
typeof(Dictionary<string, object>));
上記はFirestore側でmapとして保存してあるデータを変換する場合。
一応そのほか全種掲載しておきます。
フィールドタイプ string
すでに記述済みではありますが、改めて。
docDictionary["path"].ToString();
フィールドタイプ number
number(数字)
はint
などに変換できます。float
とかも同じ感じでいけます。
(int) Convert.ChangeType(docDictionary["path"], typeof(int));
フィールドタイプ boolean
boolean(ブール値)
はbool
に変換できます。
(bool) Convert.ChangeType(docDictionary["path"], typeof(bool));
フィールドタイプ map
map(マップ)
はDictionary<string, object>
に変換できます。Valueをいきなりint
などにしての変換はできないので、まずはDictionary<string, object>
に変換してから扱うようにしましょう。
(Dictionary<string, object>) Convert.ChangeType(docDictionary["path"], typeof(Dictionary<string, object>));
フィールドタイプ array
array(配列)
は配列とは名ばかりにList<object>
に変換できます。もし、本当に配列として扱いたいのであれば、いったんリストで読み込んだ後に配列に変換してあげる必要があります。
(List<object>) Convert.ChangeType(docDictionary["path"], typeof(List<object>));
フィールドタイプ null
値がnullの際はこれに該当します。例えばint[]
で定義した配列を何も初期化せずに渡した場合、サーバー側でnull
タイプとして保管されます。nullを取りうるarrayやreferenceはnullチェックをすべきでしょう。
フィールドタイプ timestamp
timestamp(タイムスタンプ)
はTimestamp
に変換できます。いきなりDateTime
やDateTimeOffset
には変換できません。キャストエラーになります。これらにしたい際は、Timestamp
に変換後に、.ToDateTime()
などを用いてあげましょう。
(Timestamp) Convert.ChangeType(docDictionary["path"], typeof(Timestamp));
フィールドタイプ geopoint
geopoint(地理位置情報)
はGeoPoint
に変換できます。
(GeoPoint) Convert.ChangeType(docDictionary["path"], typeof(GeoPoint));
フィールドタイプ reference
- referenceのみ調査中です。