電脳世界のケーキ屋さん

考えの甘い甘党エンジニアがいろいろ書くブログ

Python からneo4jで作成したノードのIDを取得する方法

はじめに

Python歴2日くらいの初心者が Python の neo4j-driver を触って四苦八苦した話である.
目的としては CREATE 句によって作成したノードのIDをPython側で知ることであった.

実行環境

  • Python : 3.7.0a2
    • neo4j-driber : 1.5.0
  • neo4j : 3.2.5

neo4j 側

下記のクエリでは作った直後のノードの情報はPython側には返ってきてくれない.

CREATE (:test {content:"this is test"})

どうやったら戻せるかで1時間くらい悩んだ結果, RETURN を用いれば良いことに気付いた.

CREATE (x:test {content:"this is test"}) RETURN x

これでPython側に結果として返ってくる.

Python

Python 側で値を実際に取り出すのに苦労した.そこにあるのに取り出せない非常にもどかしい状況だった.
neo4j-driver ではステートメントの結果を BoltStatementResult という型で返してくる.
そもそもこれがどういう型なのか把握するのに時間を消費した.
この公式ドキュメントneo4j.v1.StatementResult というクラスがそれに該当するということが判明.

とりあえず for record in resultprint 出力すると下記の結果を得た.

(<Node id=26527 labels={'test'} properties={'content': 'this is test'}>,)

なにやら括弧に包まれ過ぎていて, これまた解読するのに時間がかかった.
上記の表現はつまりノードクラスを1つ保持するタプル型の変数出力であることを理解した.
タプル型はインデクサでアクセスできるようなので, x[0] で素の Node クラスを取得できることになる.
あとは Node.id で値を得られる訳である.

結論として, CREATE句によって作成したノードのIDをprintしたい場合は以下のようにすれば実現できる.

statement = "CREATE (x:test {content: {content}}) RETURN x"
with driver.session() as session:
  with session.begin_transaction() as tx:
    for record in tx.run(statement, {"content": "this is test"})
      print(record.values()[0].id)

追記

neo4j側のクエリを下記のようにするともう少しスマートかもしれないしそうでないかもしれない.

CREATE (x:test {content:"this is test"}) RETURN ID(x)

こうすると Python側にはIDの値だけが戻ってくる.
この場合は下記のようにアクセスすれば取得できる.

print(record["ID(x)"])

キーがそのまま過ぎて扱い辛い. スマートになったといえば疑問ではあるがこういう手法もある.

WITH 句を利用するともう少し綺麗にできる.

CREATE (x:test {content:"this is test"})
  WITH ID(x) as id
  RETURN id

おわりに

今回はユーザに「ID~~でデータベースに登録しました」という通知を行いたかったため, このようなことに思い至った次第である.
ただ, neo4j はグラフ型データベースであり, そもそもインデックスをこのように振り回すのはナンセンスなのかもしれない.
neo4j についても Python についてもまだまだ初心者にすら至っていないようなレベルなので, また何か改善案があれば追記する.