表題の通りです。結論としては、upsert mutation
を使います。
前提
例えば、ブラウザ上で不特定の人数にアンケートを行う場合のテーブルの構造やクエリについて考えてみます。
テーブルには「回答のid(answerId)、回答(answer)、その解答をしたユーザー(userId)、その回答に対する質問番号(questionId)」の4つのカラムがあればよいです。
例) 回答テーブル
answerId | answer | userId | questionId |
---|---|---|---|
1 | ① | ユーザーA | 質問1 |
2 | ② | ユーザーB | 質問1 |
3 | ② | ユーザーA | 質問2 |
4 | ⑤ | ユーザーC | 質問3 |
さて、ユーザーが回答する際には、「まだ回答していない質問に答える(=DBに新しく回答を追加する)」ときと、「すでに回答したものを修正する(=DBに既に存在するレコードを更新する)」ときの2パターンがあります。クエリ的には、前者の場合はinsert mutation
で、後者の場合はupdate mutation
となります。
insert
とupdate
をいちいち切り替えるのは面倒だなと思いながらHasuraのドキュメントを読んでいたら、upsert mutation
というものがありました。
詳しいqueryの記述例などは上記のリンクからドキュメントを読んでもらえればと思います。
ざっくりと説明しておくと、
insert
用のクエリにon_conflict
を追加します。そしてconstraint
には「レコードが既にある」とみなすために参照するカラムがどれであるかを指定します。
レコードを追加する際にconstraint
に指定されたカラムの値を参照し、同じ値を持っているレコードがあればそのレコードを更新する。なければ新しいレコードとして追加する、といった具合です。
insert_answers(
objects: { answerId: $answerId, answer: $answer, userId: $userId, questionId: $questionId }
on_conflict: { constraint: answers_userId_questionId_key, update_columns: answer }
)
ちなみに、constraint
に指定するのはカラム名ではなく、ユニークキーとして設定されているカラムのキー名?です。
例えば以下の場合は、constraint: answerId
ではなく、constraint: answers_pkey
と指定します。どんな名前が振られているかは、テーブルのModifyから確認することができます。
先ほど例として挙げた回答テーブルでは、ユニークなキーは回答idとなっています。しかし、回答idはレコードがテーブルに追加されたときに生成されるものであるため、constraint
に指定することはできません。
そのため、今回はユニークなキーとして、ユーザーidと質問idの複合キーを使いました。
テーブルのModifyのUnique Keysで、Add a new unique keysを選択し、ユーザーidと質問idを追加することで、ユニークな複合キーとしてキー名が生成されます。
つまり今回の場合は、constraint: answers_userId_questionId_key
としてクエリを実行すればよいです。