Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.
03-07-2020 01:16 PM
Hi,
Running into a brick wall using the javascript driver to migrate JSON data into Neo4j.
Simple transaction wrapper:
const n4jTxn = ({ neo4jDriver, unitsOfWork }) => {
const session = neo4jDriver.session({ defaultAccessMode: neo4j.session.WRITE});
return session.writeTransaction((txn) => {
const promises = _.map(unitsOfWork, (uow) => {
console.log(`[n4jTxn] unitOfWork: ${JSON.stringify(uow, {}, 2)}`);
return txn.run({ text: uow.query, parameters: uow.parameters});
});
return Promise.all(promises);
}).then((results) => {
console.log(`[n4jTxn] result: ${JSON.stringify(results, {}, 2)}`);
session.close();
return results;
}).catch((error) => {
session.close();
throw error;
});
};
Yields the dreaded "Cannot merge node using null property value for xyz..."
[n4jTxn] unitOfWork: {
"query": "UNWIND $users AS u MERGE (newUser:User { _id: u._id, name: u.name, email: u.email, accountId: u.accountId }) RETURN newUser",
"parameters": {
"users": [
{
"_id": "5cc1efebe13133250e8bc9c6",
"name": "Admin 1",
"email": "admin1@example.com",
"accountId": "de34d0a8-4715-40aa-8cc5-dasdfjad"
},
{
"_id": "5cc1efebe13133250e8bc9c9",
"name": "GC 40",
"email": "gc40@examplecom",
"accountId": "b70f5117-4f1f-45a9-8278-addkadk"
},
{
"_id": "5cc1efebe13133250e8bc9cb",
"name": "Architect 1",
"email": "architect1@example.com",
"accountId": "3937f941-040d-40ed-b1ee-alsdfa"
}
]
}
}
[migrate -- migrateUsers] Neo4jError: Cannot merge node using null property value for accountId.
Any thoughts on what's going on? Thanks.
Solved! Go to Solution.
03-07-2020 07:55 PM
For the record, the issue seems to be that the js driver is not correctly serializing the parameters. Re-implementing the transaction wrapper to use the HTTP interface works as expected:
const urllib = require('urllib');
const txnURL= "http://localhost:7474/db/neo4j/tx/commit";
const n4jTxn = async (statements) => {
//
// expect statements to be an array of statement + query dicts:
//
// statements: [{statement: query, parameters: params }] ;
const data = { statements };
// console.log(`[n4jTxn] payload data: ${JSON.stringify(data, {}, 2)}`);
return urllib.request(txnURL, {dataType: 'json', contentType: 'json', auth: AUTH_STRING, method: 'POST', data })
.catch((error) => {
console.error(`[n4jTxn] error: ${JSON.stringify(error, {}, 2)}`);
throw error;
})
.then((results) => {
console.log(`[n4jTxn] results: ${JSON.stringify(results, {}, 2)}`);
return results;
});
};
03-07-2020 01:59 PM
Specifically -- you don't have any xyz properties in there. It's not clear if you meant that as a generic example or not, because no xyz properties are mentioned in your code.
More generally -- MERGE is a combination of MATCH and CREATE. MERGE needs to first try to find nodes by a particular property set, so you can't use null property values with merge because of special details about how null operates. For example this won't work:
MERGE (f:Foo { x: null })
So the answer is to migrate any properties that might be null outside of the MERGE clause. Like this:
MERGE (f:Foo { id: 1 })
SET f.otherProp = $param
This will work even if $param is null, where MERGE (f:Foo { id: 1, otherProp: $param })
would fail.
03-07-2020 02:36 PM
The second code block shows the parameters getting passed on the wire, in addition to the query itself. I'm trying to apply this pattern to my data: Creating Nodes from a list parameter.
03-07-2020 07:55 PM
For the record, the issue seems to be that the js driver is not correctly serializing the parameters. Re-implementing the transaction wrapper to use the HTTP interface works as expected:
const urllib = require('urllib');
const txnURL= "http://localhost:7474/db/neo4j/tx/commit";
const n4jTxn = async (statements) => {
//
// expect statements to be an array of statement + query dicts:
//
// statements: [{statement: query, parameters: params }] ;
const data = { statements };
// console.log(`[n4jTxn] payload data: ${JSON.stringify(data, {}, 2)}`);
return urllib.request(txnURL, {dataType: 'json', contentType: 'json', auth: AUTH_STRING, method: 'POST', data })
.catch((error) => {
console.error(`[n4jTxn] error: ${JSON.stringify(error, {}, 2)}`);
throw error;
})
.then((results) => {
console.log(`[n4jTxn] results: ${JSON.stringify(results, {}, 2)}`);
return results;
});
};
All the sessions of the conference are now available online