仅当neo4j中不存在节点时,如何创建新节点

时间:2015-09-17 17:12:04

标签: java neo4j spring-data-neo4j

我正在使用neo4j和vertx。

我正在使用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;
    }

谢谢你, 射线。

2 个答案:

答案 0 :(得分: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

此版本将首先搜索节点(并在需要时创建),然后才在该节点上设置属性。

答案 1 :(得分:3)

使用MERGE代替CREATE

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

[更新1]

以下是如何修改addDistanceUserListByForUserId()的示例,以便它返回包含已创建/现有Map<String, Object>的属性的User

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的现有User但也具有其他属性,则会导致name错误。

要解决此问题,请尝试使用此更复杂的查询替换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的{​​{1}},则不会跳过查询的其余部分(但name将为{{ 1}})。
  • 然后创建一个n集合,告诉NULL子句是否应该创建新的todo节点。如果FOREACH集合为空,则User子句不执行任何操作。
  • 修改子句(如FOREACH)和后续todo子句之间需要有WITH子句。我们并不需要向前传递任何内容,所以我们只使用FOREACH,因为我们已经方便了。
  • 我们需要另一个MATCH查询,因为我们想要返回找到的节点,或者我们刚刚创建的节点。但除非我们执行另一个todo,否则无法获取MATCH创建的节点。