2015-09-17 27 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 

这个版本将搜索节点(创造如有必要)在第一,并在该节点上只有然后设置属性。