Closed10

FirestoreでDocumentReferenceをもたせる

sukedonsukedon

Firestoreは他のパス(RDBでいうところの他のテーブル)のデータを参照する際に、外部キーではなくいい感じの機能があるらしい。
よくわかってないからまとめる

sukedonsukedon

https://tech-blog.sgr-ksmt.org/2019/12/31/160623/
参考になる記事

FirestoreはNoSQLデータベースなわけで、NoSQLではRDBでいうところのレコードを「ドキュメント」と呼ぶらしい

DocumentReference

この型を使えば他ドキュメントの参照を持たせることができる。

sukedonsukedon

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型で指定した部分はパスが書かれてますね

sukedonsukedon

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をクライアント側で保持しておいて都度使う
    とかの方針がいいのかな。
sukedonsukedon

userのdocumentIdをそのままアプリ内のユーザーidにしちゃうのはなんか気持ち悪いしセキュリティ的にも良くない気がする..?
どうしようかな。被ることは無さそうだし、使ってしまうか。
セキュリティルールをちゃんと設定しよう。
認証でFirebaseAuthenticationは使わないけど、その状態でセキュリティルールを設定して効果があるんだろうか?

sukedonsukedon

とりあえず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);
}

sukedonsukedon

というわけで階層と各ドキュメントの構造を決めたらあとはモデルクラスを作れば良さそう。その作業に入る_(:3 」∠ )_

このスクラップは2021/03/23にクローズされました