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

How to create new node only if node is not existed in neo4j

我正在使用 neo4j 和 vertx。

我正在使用 neo4j-jdbc。

我设法创建了用户,但我如何才能 "upgrade" 此查询仅在该用户不存在的情况下创建新用户(具有唯一索引)。 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;
    }

谢谢, 雷.

使用MERGE代替CREATE:

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

[更新 1]

以下示例说明如何修改 addDistanceUserListByForUserId(),使其 return 成为包含 created/existing 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 这样如果没有找到具有指定 nameUser ,则不会跳过其余的查询(但 nNULL).
  • 然后它创建一个 todo 集合,它将告诉 FOREACH 子句它是否应该创建新的 User 节点。如果 todo 集合为空,FOREACH 子句不执行任何操作。
  • 修饰子句(如FOREACH)和后续的MATCH子句之间需要有一个WITH子句。我们真的不需要向前传递任何东西,所以我们只使用 todo 因为我们已经有了它。
  • 我们需要另一个 MATCH 查询,因为我们想要 return 找到或刚刚创建的节点。但是没有办法得到由 FOREACH 创建的节点,除非我们再做一个 MATCH.

您应该使用 MERGE 而不是 CREATE。如果它不存在,这将创建节点。如果节点已经存在 - 那么 MERGE 将像正常的 MATCH 操作一样。

重要提示: 您应该在 {} 属性语法中仅使用具有唯一约束的属性。 Neo4j 将合并 {} 中具有相同属性的节点。

如果在 合并 节点后要在节点 上设置其他数据,则:

MERGE (user:User {name: "John", age: 20}) - 错误的方式。因为数据库中没有这样的 nameage 属性 组合的节点,数据库将尝试创建该节点。这将导致 ConstraintViolation 因为这样的 name 已经存在。

正确版本:

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

这个版本首先会搜索节点(如果需要的话会创建),然后才在那个节点上设置属性。