我正在使用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;
}
谢谢你, 射线。
答案 0 :(得分:4)
您应该使用MERGE
代替CREATE
。如果节点不存在,这将创建节点。如果节点已存在 - 那么MERGE
将像普通MATCH
操作一样。
重要提示:您应该只使用{}
属性语法中具有唯一约束的属性。 Neo4j将合并{}
中具有相同属性的节点。
如果在合并后要在节点上设置其他数据,则:
MERGE (user:User {name: "John", age: 20})
- 错误的方式。由于数据库中没有具有此类name
和age
属性组合的节点,因此数据库将尝试创建该节点。这将导致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
创建的节点。