2015-09-17 58 views
2

存在我使用的Neo4j和vertx新節點。如何創建只有當節點未在Neo4j的

我使用的Neo4j-JDBC。

我設法創建用戶,但我怎麼能「升級」此查詢來創建新用戶(具有唯一索引),只有當用戶的心不是存在。 userId應該是主鍵。

private final Logger logger = Logger.getLogger(Neo4jRepo.class); 
    private Connection conn = null; 

    public Neo4jRepo() { 
     logger.debug("Neo4jRepo, Init"); 
     try { 
      Class.forName("org.neo4j.jdbc.Driver"); 
      conn = DriverManager.getConnection("jdbc:neo4j://localhost:7474/"); 
     } catch (SQLException e) { 
      throw new RuntimeException(e); 
     } catch (ClassNotFoundException e) { 
      throw new RuntimeException(e); 

     } 
    } 
.. 
public boolean addDistanceUserListByForUserId(String userId) { 
     try { 
      final PreparedStatement ps = conn.prepareStatement("create (n:User {name:{1}})"); 
      ps.setString(1, "userId"); 
      ps.execute(); 

     } catch (SQLException e) { 
      throw new RuntimeException(e); 
     } 
     return true; 
    } 

謝謝你, 射線。

+0

如果你使用neo4J作爲本地主機,你應該注意neo4j嵌入式,更好的性能。 – Supamiu

+0

neo4j將作爲外部服務。我們想過要嵌入它。但是我們失去了GUI和其他東西。你認爲嵌入式比內置式更好嗎? – rayman

+0

嵌入式是更好的fi你是在同一個服務器上:) GUI可以使用嵌入式進行檢索:) – Supamiu

回答

3

使用MERGE代替CREATE

"MERGE (n:User {name:{1}})" 

[UPDATE 1]

以下是如何修改addDistanceUserListByForUserId()一個例子,使得其返回包含所創建的/現有User的性質的Map<String, Object>

public Map<String, Object> addDistanceUserListByForUserId(String userId) { 
    try { 
     final PreparedStatement ps = conn.prepareStatement(
      "MERGE (n:User {name:{1}}) RETURN n"); 
     ps.setString(1, "userId"); 
     ResultSet rs = ps.executeQuery(); 
     if (rs.next()) { 
      return (Map<String, Object>) rs.getObject("n"); 
     } 
    } catch (SQLException e) { 
     throw new RuntimeException(e); 
    } 
    return null; 
} 

[更新2]

在您的具體情況,因爲你有:User(name)唯一性約束,而現有User節點可以有比其他name性能 - 簡單的查詢MERGE (n:User {name:{1}})可能導致ConstraintViolation錯誤如果存在具有相同name的現有User,但也具有其他屬性。

要解決這個問題,嘗試用這種更復雜的查詢替換MERGE聲明:

OPTIONAL MATCH (n:User { name:{1} }) 
WITH (CASE WHEN n IS NULL THEN [1] ELSE [] END) AS todo 
FOREACH (x IN todo | CREATE (:User { name:{1} })) 
WITH todo 
MATCH (n:User { name:{1} }) 
RETURN n; 

下面是這個查詢的解釋:

  • 它使用OPTIONAL MATCH因此,如果User與找不到指定的name,查詢的其餘部分未被跳過(但n將爲NULL)。
  • 然後,它創建了一個todo集合會告訴FOREACH條款是否應創建新的User節點。如果todo集合爲空,則FOREACH子句不執行任何操作。
  • 需要有改性條款(像FOREACH)和隨後的MATCH條款之間的WITH子句。我們並不需要向前傳遞任何東西,所以我們只使用todo,因爲我們已經有了它。
  • 我們需要另一個MATCH查詢,因爲我們要返回要麼發現,或者說,我們剛剛創建的節點。但是沒有辦法獲得由FOREACH創建的節點,除非我們做另一個MATCH
+0

如果這個節點已經存在,我該如何檢索它? – rayman

+0

查看我的更新回答。我沒有測試過這個代碼,但它看起來應該可以工作。 – cybersam

+0

雖然有效,但我對名稱使用了獨特的限制,而且我還有其他一些名爲age的屬性。所以如果用戶已經存在的名稱,但有差異,我嘗試合併我得到這個異常:執行cypher語句的錯誤[{code = Neo.ClientError.Schema.ConstraintViolation,message =節點15已經存在標籤用戶和財產「名稱」= [Jossef]}] – rayman

4

您應該使用MERGE而不是CREATE。這將創建節點,如果它不存在。如果節點已經存在 - 那麼MERGE將像正常的MATCH操作一樣行事。

重要信息:只應在{}屬性語法中使用具有唯一約束的屬性。 Neo4j將合併在{}中具有相同屬性的節點。錯誤的方法 -

MERGE (user:User {name: "John", age: 20})

如果您有其他數據節點合併,然後進行設置。因爲數據庫中沒有節點,所以nameage屬性組合和數據庫將嘗試創建該節點。這將導致ConstraintViolation,因爲這樣的name已經存在。

正確的版本:

MERGE (user:User {name: "John"}) 
SET user.age = 20 

這個版本將搜索節點(創造如有必要)在第一,並在該節點上只有然後設置屬性。