这是我想象的精简版你正在做的事情的一个简短的 Python 位
import neo4j
import neo4j.exceptions
def main():
uri = "neo4j://localhost:7687"
user = "neo4j"
password = "pass"
auth = neo4j.basic_auth(user, password)
with neo4j.GraphDatabase.driver(uri, auth=auth) as driver:
with driver.session() as session:
create_query = "CREATE (:Person {name: $name})"
match_query = "MATCH (p:Person {name: $name}) RETURN p"
merge_query = ("MERGE (p:Person {name: $name}) "
"ON CREATE "
" SET p.name=$name2")
wrong_merge = ("MERGE (p:Person {name: $name}) "
"ON CREATE "
" SET p.name='created' "
"SET p.name=$name2")
session.run("CREATE CONSTRAINT person_name IF NOT EXISTS "
"FOR (p:Person) REQUIRE p.name IS UNIQUE")
session.run("MATCH (n) DETACH DELETE n")
session.run(create_query, name="Alice")
session.run(create_query, name="Bob")
try:
session.run(create_query, name="Alice")
assert False # should not get here
except neo4j.exceptions.Neo4jError as e:
print(f"Fails as expected: {e}")
# noop because Alice already exists
session.run(merge_query, name="Alice", name2="Alice2")
assert len(list(session.run(match_query, name="Alice"))) == 1
assert not list(session.run(match_query, name="Alice2"))
# finds Alice and always updates
session.run(wrong_merge, name="Alice", name2="Alice2")
assert not list(session.run(match_query, name="Alice"))
assert len(list(session.run(match_query, name="Alice2"))) == 1
# You can't rename Alice to Bob, bcs. Bob already exists
try:
session.run(wrong_merge, name="Alice2", name2="Bob")
assert False # should not get here
except neo4j.exceptions.Neo4jError as e:
print(f"Fails as expected: {e}")
if __name__ == "__main__":
main()
查看wrong_merge 查询。第二个SET 总是被执行,不管MERGE 是创建一个新节点还是匹配一个现有节点。我强烈怀疑name 出现在您的other_props 中,因此试图将名称更改为已经存在的名称。
最后,无论是否是这种情况,我建议您习惯于通过字符串连接或插值来构建任何数据库查询(无论是哪个数据库)。几乎所有的数据库都提供了一种参数化查询的方法。这有两个好处:
- 数据库可以优化你的查询,只是参数不同
- 您永远不会陷入使自己容易受到查询注入攻击的情况。