FirestoreでDocumentReferenceをもたせる
Firestoreは他のパス(RDBでいうところの他のテーブル)のデータを参照する際に、外部キーではなくいい感じの機能があるらしい。
よくわかってないからまとめる
参考になる記事
FirestoreはNoSQLデータベースなわけで、NoSQLではRDBでいうところのレコードを「ドキュメント」と呼ぶらしい
DocumentReference
この型を使えば他ドキュメントの参照を持たせることができる。
対象のドキュメントまでのルートからのパスを持ってる。
少し前にFirestore使ったときのメモが残っていたけど、このときは投稿のみを管理する形式だった
L users
L posts
みたいな構成の前提で、ユーザーの登録→投稿をやるとこうなる
// ユーザーの登録
Dictionary<string, object> userData = new Dictionary<string, object>()
{
{"name", "testuser"},
{"createdAt", Timestamp.GetCurrentTimestamp()},
};
// AddSyncをするとDocumentReference型で返ってくる
var user = await FirebaseFirestore.DefaultInstance.Collection("users").AddAsync(userData);
Dictionary<string, object> data = new Dictionary<string, object>()
{
{"author", user},
{"content","hoge"},
{"createdAt", Timestamp.GetCurrentTimestamp()},
};
await FirebaseFirestore.DefaultInstance.Collection("posts").AddAsync(data);
Firestore側で見てみるとこんな感じに。DocumrneReference型で指定した部分はパスが書かれてますね
L users
L posts
の構成で、今度は既存のユーザーをドキュメントidを元にさがして、新しく投稿を追加してみる。
string userDocumentId = "JXvB4DorCwWRsPK0SXQS";
DocumentReference userReference = FirebaseFirestore.DefaultInstance.Collection("users").Document(userDocumentId);
DocumentSnapshot snapshot = await userReference.GetSnapshotAsync();
if (snapshot.Exists)
{
Dictionary<string, object> data = new Dictionary<string, object>()
{
{"author", snapshot.Reference},
{"content","hoge"},
{"createdAt", Timestamp.GetCurrentTimestamp()},
};
await FirebaseFirestore.DefaultInstance.Collection("posts").AddAsync(data);
}
ちゃんと指定したユーザーでpostsに追加されてる。
なので、userについては
- 最低限userDocumentIdはクライアント側で保存する
- userの使用頻度が高い場合は起動時に取得したDocumentReferenceをクライアント側で保持しておいて都度使う
とかの方針がいいのかな。
userのdocumentIdをそのままアプリ内のユーザーidにしちゃうのはなんか気持ち悪いしセキュリティ的にも良くない気がする..?
どうしようかな。被ることは無さそうだし、使ってしまうか。
セキュリティルールをちゃんと設定しよう。
認証でFirebaseAuthenticationは使わないけど、その状態でセキュリティルールを設定して効果があるんだろうか?
とりあえずusers・postsと投稿することは出来たけど、usersがpostsを持つ、という構成にしたい。
つまり、postsをusersのサブコレクションとして扱いたい。
users - user - posts
L user - posts
L user - posts
みたいな
string userDocumentId = "JXvB4DorCwWRsPK0SXQS";
DocumentReference userReference = FirebaseFirestore.DefaultInstance.Collection("users").Document(userDocumentId);
DocumentSnapshot userSnapshot = await userReference.GetSnapshotAsync();
if (userSnapshot.Exists)
{
Dictionary<string, object> data = new Dictionary<string, object>()
{
{"author", userSnapshot.Reference},
{"content", "hoge"},
{"createdAt", Timestamp.GetCurrentTimestamp()},
};
await userSnapshot.Reference.Collection("posts").AddAsync(data);
}
毎回Dictionaryを定義するのは微妙だなと思い調べる。
FireStore側で用意されてるAttributeを使えば読み書きともによしなにやってくれるみたい。
詳解
というわけで階層と各ドキュメントの構造を決めたらあとはモデルクラスを作れば良さそう。その作業に入る_(:3 」∠ )_