質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

Q&A

解決済

1回答

764閲覧

FirestoreでドキュメントIDとは別に、ユーザ作成のdisplayIDを作成する手法

wine

総合スコア18

Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

0グッド

1クリップ

投稿2019/07/12 10:46

編集2019/07/12 14:52

FirestoreにドキュメントIDとは別に、もう一つユーザが作成するdisplayIDを保存したいと思っています。
このIDは作成後の編集は出来ないようにする予定ですが、後々、編集機能をつけたくなる可能性もあるものです。
Twitterの@IDのようなもので、小文字と大文字は見分けません。

ドキュメント例
/users/{uid}
{
"displayId":"CatIsVeryCute",
"description":"Cat lover.",
"createTime":ServerTimestamp
}

現状、ドキュメントに
"lowerCaseDisplayId":"catisverycute",
のように、小文字のフィールドを追加し、クライアント側で

swift

1 let lowerCaseDisplayId = "CatIsVeryCute".lowercased() 2 let docRef = db.collection("users").whereField("lowerCaseDisplayId", isEqualTo: lowerCaseDisplayId) 3 docRef.getDocuments { (snapshot, error) in 4 if let error = error { 5 // エラー処理 6 return 7 } 8 if snapshot?.documents != [] { 9 // 既存のIDだから、他のIDを作成してください! 10 return 11 }else{ 12 // 使えるIDです! 13 return 14 } 15 }

と確認処理をさせて、サーバ側では、セキュリティルールで確認しようとしたのですが、セキュリティルールで確認する方法が見つかりませんでした。

そこで、今後の策としては
0. lowerCaseDisplayIdをドキュメントIDにして、セキュリティルールのexists()で確認
一意性は保証される。しかし、あとで変える機能が欲しくなった場合には苦労する。また、ユーザ作成なので、ホットスポットの要因になる可能性がある?
\n
0. Callable Functionsで確認・作成する
マルチスレッド処理なので、精密には一意性を保証できないが、クライアントだけの確認より、悪意を持って確認処理をしないで作成することができない分、マシなはず。。。
\n
0. クライアントだけの確認で妥協する
普通に使っている分には、ほぼ大丈夫な気がするが、悪意を持って同じIDを作成することは可能。クライアント側で、createTimeが古いユーザを表示するようにすれば、問題にならないかも?

の3つを考えています。

どれがいいか悩んでおり、アドバイスをいただければ幸いだと思っております。

また、セキュリティルールだけで一意性を保証できる方法をご存知の方は、ご教授いただけると大変ありがたいです。

よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

正解はないと思いますがアドバイスとして。

lowerCaseDisplayIdをドキュメントIDにして、セキュリティルールのexists()で確認

一意性は保証される。しかし、あとで変える機能が欲しくなった場合には苦労する。

これに対してですが以下が良いと思います。

  1. usersコレクションとは別に、displayIdだけを管理するdisplayIdsといったようなルートコレクションを作成する

  2. displayIdsに対してセキュリティルールを設定する。

match /users/{userID} { allow update: if request.auth.uid == userID && ( request.resource.data.displayId == resource.data.displayId || !exists(/databases/$(database)/documents/displayIds/$(request.resource.data.displayId)) ); }

あとは、クライアント(またはFunctions)からdisplayIdを登録・更新する際に、トランザクションの中でざっくりにはなりますが次の処理を行えば良いかと思います。

  1. displayIdsに対してdisplayIdの存在確認 → 存在しなければ2へ
  2. 更新の場合、displayIdsに対して変更前のdisplayIdを削除&変更後のdisplayIdを登録
  3. usersに対してdisplayIdを登録・更新

投稿2019/07/14 10:07

xenbeat

総合スコア4258

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

wine

2019/07/14 11:17

一意性をexists()で確保しつつ、usersのドキュメントIDは固定になるため、変更しやすいまま実装できる訳ですね。 一意性確保を主眼として1つのルートコレクションを作成するという手法は、一見するだけでは無駄が多く感じられて、ほぼ考えることも出来なかったため、大変勉強になりました。 聞いてみると、最良の方法という気がしますし、視野を広く持って考えなければと反省しました。 この方法で実装しようと思います。 ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問