2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

株式会社ゆめみの24卒Advent Calendar 2023

Day 4

neo4jのMERGEでつまずいた話

Last updated at Posted at 2023-11-27

はじめに

 本記事では,私がneo4jのMERGE句の利用でつまずいたので,備忘録とカレンダーの作成がてらMERGE句の使い方をまとめていこうと思います

MERGE関連の公式ドキュメント

MERGE句とは

 MERGE句は,ノードやリレージョンが存在するときは上書きを,存在しない時は新規に作成を行ってくれる構文になります

基本的な使い方

公式より

MERGE (n:Label {name: $value})
ON CREATE SET n.created = timestamp()
ON MATCH SET
  n.counter = coalesce(n.counter, 0) + 1,
  n.accessTime = timestamp()

MERGEを利用しない場合

作成時

CREATE (n:Label {name: $value, created: timestamp()}

更新時

MATCH (n:Label)
WHERE n.name =  $value
SET
  n.counter = coalesce(n.counter, 0) + 1,
  n.accessTime = timestamp()

or

MATCH (n:Label {name: $value})
SET
  n.counter = coalesce(n.counter, 0) + 1,
  n.accessTime = timestamp()

プログラムから利用することを考えると,場合分けをしないで使えるMERGE句のありがたみが分かると思います

発生した問題

 現在作成中のプログラムは,ユーザーの関係を管理するためneo4jを採用しました.Userの持つプロパティは一部省略しますが以下のようになっています

  • id:ユーザーID ユニーク
  • displayName:表示名
  • createdAt:Userの作成時刻

idはユニークですので,neo4jに以下の設定を行いました

CREATE CONSTRAINT unique_user_id IF NOT EXISTS
FOR (u:User)
REQUIRE u.id IS UNIQUE

ここで,プログラム側の実行時に公式アカウントを作成済みでなければ作成する機能が欲しかったので,以下のようなcypherを実行するプログラムの作成を行いました

MERGE (:User {
  id: "official",
  displayName: "公式",
  createdAt: datetime()
})

一回目の実行では正常に成功し,以下のようなUserが作成されました

{
  "id": "official",
  "displayName": "公式",
  "createdAt": "2023-12-01T00:00:00Z"
}

期待通りの結果が得られ,ヨシッとこの時までは思っていました.が,次の機能を開発し,サーバーを再起動すると以下のエラーが出るようになりました.

Node(0) already exists with label `User` and property `id` = 'official'

このエラーはユニーク制約に引っかかって出力されるエラーになります.テストのために以下のようなコードを作成し,検証を行いました

MERGE (:Test {prop: "test"})

しかし,こちらのコードでは何回実行してもエラーにはなりませんでした.ここで私は,「MERGE句の内部処理で一回同じidのノードを作成してしまっているのではないか」とあたりをつけてバグの解決策を調べ始めました.自分のプログラムは絶対あってるって思っちゃうよね
 しかし,neo4jの公式やライブラリのissueをみても解決せず...ここでやっと自分のプログラムが間違っているのではないかと考え始めました.

解決

 よくよく考えてみると,MERGE句はどこで新規か上書きかの判別を行っているのかといった疑問が浮かびました.調べた結果が以下になります(唐突)

MERGE (n:Label {ここに一致条件を列挙})
ON CREATE SET
  ここに新規作成時に設定するプロパティを列挙
ON MATCH SET
  ここに更新時に設定するプロパティを列挙

私のプログラムを修正すると以下のようになります

MERGE (u:User {id: "official"})
ON CREATE SET
  u.displayName = "公式",
  u.createdAt = datetime()
})

まとめ

 今回,MERGE句の利用でつまずいたので,MERGE句の使い方についてまとめてみました.直接的にエラーで指摘されないと,自分のコードを間違ってると思えないのは悪い癖ですね.私失敗しないのでって言えるエンジニアになりたい...(先は長そう)
 記事にまとめてみると,その時自分は何を考えてそうしたかや,どうするべきだったか反省出来て良かったです.ゆめみの24卒カレンダーに参加しているので,また何かしら問題に詰まったら,復習がてら記事を書いてこうと思います.では!

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?