I'm currently working on a Node.js project that involves creating nodes in Neo4j using the 'MERGE' statement. However, I've noticed that even when I use 'MERGE' to ensure that duplicate nodes are not created, the statement sometimes still creates duplicates.
I've checked the Neo4j documentation and searched for similar issues online, but I haven't found a solution to this problem. Can anyone help me understand why this is happening and how I can prevent it from happening in the future? I provide the code repository on here.
Any suggestions or insights would be greatly appreciated. Thank you!
Here's the code I'm using:
const neo4j = require('neo4j-driver')
const url = `neo4j://test-neo4j:7687`;
(async ()=>{
console.log(`start connect to neo4j : ${url}`);
const driver = neo4j.driver(
url,
neo4j.auth.basic('neo4j', 'nodejs_to_neo4j')
)
const endFn = (session)=>{
setTimeout(()=>{
session.close();
driver.close();
console.log(`end connect to neo4j : ${url}`);
}, 3000);
};
setTimeout(async ()=>{
for(let i= 0; i < 10 ; i++){
const session = driver.session();
let userId = '123';
let nameParam = 'John Doe';
const query = 'MERGE (n:Person {user_id: $userId, name: $nameParam}) RETURN n';
console.log(
`query(${i + 1}): ${query}`
.replace('$userId', userId)
.replace('$nameParam', nameParam)
);
let dictResult = session.run(query, { userId, nameParam });
if(i === 9) {
dictResult.then(endFn(session));
} else {
dictResult.then();
}
}
}, 1000);
})();
I expect this code to only create a new node if a node with the same properties does not already exist in the database. However, in some cases, the code creates a new node even if a node with the same name already exists.
It is important to understand that MERGE on a single node pattern may create duplicates unless there is a uniqueness constraint.
Therefore, you need to make sure you have a uniqueness constraint on :Person(user_id)
:
CREATE CONSTRAINT Person_user_id FOR (p:Person) REQUIRE p.user_id IS UNIQUE;
You should also change your query so that you use MERGE
on only the constrained property, user_id
:
MERGE (n:Person {user_id: $userId}) ON CREATE SET n.name = $nameParam RETURN n
Finally, you need to close every session
, not just the last one. When you do not close a session it leaks resources. The recommended approach is to use try
context blocks to ensure that every session is always closed.