简体   繁体   中英

Property values can only be of primitive types or arrays thereof in Neo4J Cypher query

I have the following params set:

:params "userId":"15229100-b20e-11e3-80d3-6150cb20a1b9",
"contextNames":[{"uid":"94e71bf0-1e7d-11e9-8f33-4f0c99ea0da1","name":"zhora"}],
"statements":[{"text":"oranges apples bananas","concepts":["orange","apple","banana"],
"mentions":[],"timestamp":15481867295710000,"name":"# banana","uid":"34232870-1e7f-11e9-8609-a7f6b478c007",
"uniqueconcepts":[{"name":"orange","suid":"34232870-1e7f-11e9-8609-a7f6b478c007","timestamp":15481867295710000},{"name":"apple","suid":"34232870-1e7f-11e9-8609-a7f6b478c007","timestamp":15481867295710000},{"name":"banana","suid":"34232870-1e7f-11e9-8609-a7f6b478c007","timestamp":15481867295710000}],"uniquementions":[]}],"timestamp":15481867295710000,"conceptsRelations":[{"from":"orange","to":"apple","context":"94e71bf0-1e7d-11e9-8f33-4f0c99ea0da1","statement":"34232870-1e7f-11e9-8609-a7f6b478c007","user":"15229100-b20e-11e3-80d3-6150cb20a1b9","timestamp":15481867295710000,"uid":"apoc.create.uuid()","gapscan":"2","weight":3},{"from":"apple","to":"banana","context":"94e71bf0-1e7d-11e9-8f33-4f0c99ea0da1","statement":"34232870-1e7f-11e9-8609-a7f6b478c007","user":"15229100-b20e-11e3-80d3-6150cb20a1b9","timestamp":15481867295710002,"uid":"apoc.create.uuid()","gapscan":"2","weight":3},{"from":"orange","to":"banana","context":"94e71bf0-1e7d-11e9-8f33-4f0c99ea0da1","statement":"34232870-1e7f-11e9-8609-a7f6b478c007","user":"15229100-b20e-11e3-80d3-6150cb20a1b9","timestamp":15481867295710002,"uid":"apoc.create.uuid()","gapscan":4,"weight":2}],"mentionsRelations":[] 

Then when I make the following query:

MATCH (u:User {uid: $userId}) 
UNWIND $contextNames as contextName 
MERGE (context:Context {name:contextName.name,by:u.uid,uid:contextName.uid}) 
ON CREATE SET context.timestamp=$timestamp 
MERGE (context)-[:BY{timestamp:$timestamp}]->(u) 
WITH u, context 
UNWIND $statements as statement 
CREATE (s:Statement {name:statement.name, text:statement.text, uid:statement.uid, timestamp:statement.timestamp}) 
CREATE (s)-[:BY {context:context.uid,timestamp:s.timestamp}]->(u) 
CREATE (s)-[:IN {user:u.id,timestamp:s.timestamp}]->(context)  
WITH u, s, context, statement 
FOREACH (conceptName in statement.uniqueconcepts |  
MERGE (c:Concept {name:conceptName}) ON CREATE SET c.uid=apoc.create.uuid() 
CREATE (c)-[:BY {context:context.uid,timestamp:s.timestamp,statement:s.suid}]->(u) 
CREATE (c)-[:OF {context:context.uid,user:u.uid,timestamp:s.timestamp}]->(s)  
CREATE (c)-[:AT {user:u.uid,timestamp:s.timestamp,context:context.uid,statement:s.uid}]->(context)  )  
WITH u, s 
UNWIND $conceptsRelations as conceptsRelation MATCH (c_from:Concept{name: conceptsRelation.from}) MATCH (c_to:Concept{name: conceptsRelation.to}) 
CREATE (c_from)-[:TO {context:conceptsRelation.context,statement:conceptsRelation.statement,user:u.uid,timestamp:conceptsRelation.timestamp, uid:apoc.create.uuid(), gapscan:conceptsRelation.gapscan, weight: conceptsRelation.weight}]->(c_to)  
RETURN DISTINCT s.uid

But when I run it, I get this error:

Neo.ClientError.Statement.TypeError
Property values can only be of primitive types or arrays thereof

Anybody knows why it's coming up? My params seem to be set correctly, I didn't see they couldn't be used in this way... Thanks!

Looks like the problem is here:

...
FOREACH (conceptName in statement.uniqueconcepts |  
MERGE (c:Concept {name:conceptName})
...

uniqueconcepts in your parameter is a list of objects, not a list of strings, so when attempting to MERGE conceptName, it errors out as conceptName isn't a primitive type (or array or primitive types). I think you'll want to use uniqueConcept instead of conceptName , and in your MERGE use name:uniqueConcept.name . Check for other usages of the elements of statement.uniqueconcepts.

This answer is for other n00bs like me that are trying to put a composite datatype into a property without reading the friendly manual, and get the error above. Google points here, so I felt appropriate to add this answer.

Specifically, I wanted to store a list [(datetime, event), ...] of tuples into a property of a relation.

Potential encountered errors are:

Neo.ClientError.Statement.TypeError: Property values can only be of primitive types or arrays thereof

Neo.ClientError.Statement.TypeError: Neo4j only supports a subset of Cypher types for storage as singleton or array properties. Please refer to section cypher/syntax/values of the manual for more details.

The bottom line is well summarized in this forum post by a Neo4j staff member:

Neo4j doesn't allow maps as properties (no sub-properties allowed, basically), and though lists are allowed as properties, they cannot be lists of maps (or lists of lists for that matter).

Basically I was trying to bypass the natural functionality of the DB. There seem to be 2 workarounds:

  1. Dig your heels in as suggested here , and store the property as eg a JSON string

  2. Rethink the design, and model these kind of properties into the graph (ie being more specific with the nodes)

After a little rethinking I came up with a much simpler data model that didn't require composite properties in relations. Although option 1 may have its uses, when we have to insist against a well-designed system (which neo4j is ), that is usually an indicator that we should change course. Andres

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM