MongoDBのUnique Indexでユニークなユーザ管理を実装する
ユーザをデータベースで管理する上で、同じユーザが重複することはあまり好ましくない場合が多いです。そこで今回はMongoDBのUnique Indexというものを使ってユーザが2回目以降に登録の操作を行った場合に、代わりにログインの処理を行うという実装をしてみます。
全体像
処理の流れ
処理の流れは下図のようになります:
簡単な説明をすると、Register
Mutationで新規登録を試みます。PythonがMongoDBにMutationで持たせたデータを追加しようとすると、MongoDB側がuser_id
がCollection(RDBで言うTableのこと)内に同じuser_id
が存在するかチェックします。後にMongoDBのレスポンスに応じて処理を切り替えるという仕組みなっています。
GraphQLではステータスコードの値による処理の決定ができないので、具体的なエラーを決め打ちしてエラー処理を考えます。
(詳細)
アウトプットイメージ
Register(成功)
user_id
が存在しない場合、上図のように登録された内容と、Registerに成功したというメッセージがレスポンスとして返します。
Register(失敗:ログイン)
Register
Mutationを飛ばしたあと、もう一度リクエストを飛ばすと上図のように既に登録済みだというエラーレスポンスを返します。(エラーを返した場合の具体的なログイン処理は記載しない)
実装
Atlas UIでUnique Indexを設定
MongoDB AtlasというMongoDBのクラウドを利用します。[Database > Browse Collections > UserTable > Indexs]でユーザ管理をしているコレクションのインデックス項目へアクセスします。CREATE INDEX
をクリックして画像のようにユーザIDにunique indexを付与します。
index
は以下のように1なら昇順、-1なら降順で付与されます。用途に合わせて利用してください。
{user_id: 1} //昇順でインデックスを付与
{user_id: -1} //降順でインデックスを付与
Regsiterの処理
Registerの処理をPythonで書きます。GraphQL APIがわからない方は以下の記事がオススメです。
スキーマ
FastAPIでGraphQL APIを使用する際は以下のようにスキーマ型の定義が必要です。
@strawberry.input # Mutation
class Register:
user_id: str
user_name: str
avatar_url: str
@strawberry.type # Query
class Response:
user_id: str
user_name: str
avatar_url: str
regsiter関数
Mutationでregister
関数を定義します。
import pymongo #PythonでMongoDBを動かすためのパッケージ
#(省略)
mongo_client = MongoClient(os.gentenv("MONGO_URL"))
collection_user = mongo_client["Database"]["UserCollection"]
class Mutation:
@strawberry.field
def register(self, regist: Regsiter) -> Response:
try:
collection_user.insert_one(regsit.__dict__)
return regist
except pymongo.errors.DuplicateKeyError:
raise Exception("You are already registered. Please Login")
except Exception as e:
raise {"message": str(e)}
insert
methodでMongoDBへデータの追加をtry
で実行します。既にコレクション内に同じuser_id
が存在する場合は、PymongoがDuplicateKeyError
、つまりUniqueでないキーが存在するという旨のエラーを出力します。従ってこのエラーに対する処理としてログインの処理を追加すれば良いです。
終わりに
Unique Indexを導入することで、ユニークユーザを簡単に実装することができます。前述した通りユーザ毎に一つしかアカウントを登録できないという処理はコンテンツにおいてかなり重宝されます。ぜひ活用してみてください。
Discussion