I will like to store a collection of collection in the neo4j, but it is giving me an error so is there any other way.
Query:
CREATE (d:Dummy {property:[null,null,null,[23,32,23],null,null,[23,23,23]}) RETURN d
Error: Collections containing null values can not be stored in properties.
So how to solve this
Thanks
Your collection violates at least these 2 neo4j constraints:
Properties cannot store collections containing null values.
Properties cannot store collections with nested collections.
If you really need to store such collections, one workaround is to store the collection in stringified JSON format. For example:
CREATE (d:Dummy {property: '[null,null,null,[23,32,23],null,null,[23,23,23]]' })
RETURN d
Later on, when you need to use the property value, you will need to convert it back to a neo4j collection. The apoc.convert.fromJsonList function can be used for that purpose. For example:
MATCH (d:Dummy)
RETURN apoc.convert.fromJsonList(d.property);
Related
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:
Dig your heels in as suggested here, and store the property as e.g. a JSON string
Rethink the design, and model these kind of properties into the graph (i.e. 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
I am new to Neo4j and graph databases. I am trying to create a simple graph DB, but my MATCH query is returning null values. How do I avoid nulls or any errors in my coding?
Create DB
CREATE
(d2:CorNode:course:dscor{Cors_Name:'DataScience_Sem2',Start_Date:'January2018',No_Students:[tointeger(10)]})-[:sem2dsrelation{Name:'Semester2',Cor_Name:'Data Science',A_Y:'AY2017-18',Cor_Node:'CMM534'}]->(Rob:FLNode:course:dscor{Name_F:'Rob Lothian', Role:'Leader',Mod_code:'CMM534'}),
(d2)-[:sem2dsrelation{Name:'Semester2', Cor_Name:'Data Science',A_Y:'AY2017-18',Cor_Node:'CMM534'}]->(Eyad:FLNode:course:dscor{Name_F:'Eyad Elyan',Role:'Leader',Mod_code:'CMM534'}),
(d2)-[:sem2dsrelation{Name:'Semester2', Cor_Name:'Data Science',A_Y:'AY2017-18',Cor_Node:'CMM507'}]->(David:FLNode:course:dscor{Name_F:'David Lonie', Role:'Leader', Mod_code:'CMM507'}),
(d2)-[:sem2dsrelation{Name:'Semester2',Cor_Name:'Data Science', A_Y:'AY2017-18',Cor_Node:'CMM535'}]->(Rob),
(d1:CorNode:course:dscor{Cors_Name:'DataScience_Sem1',Start_Date:'Septemer2017',No_Students:[tointeger(25)]})-[:sem1dsrelation{Name:'Semester1',Cor_Name:'Data Science',A_Y:'AY2017-18',Cor_Node:'CMM524'}]->(Rob),
(d1)-[:sem1dsrelation{Name:'Semester1', Cor_Name:'Data Science',A_Y:'AY2017-18',Cor_Node:'CMM531'}]->(Eyad),
(d1)-[:sem1dsrelation{Name:'Semester1', Cor_Name:'Data Science',A_Y:'AY2017-18',Cor_Node:'CMM510'}]->(Ines:FLNode:course:dscor{Name_F:'Ines Arana',Role:'Leader',Mod_code:'CMM510'})
Query DB
MATCH (:dscor)-[ds1:sem1dsrelation{Name:'Semester1',Cor_Name:'Data Science'}]-(FLNode:dscor)
RETURN DISTINCT [FLNode.Name_F,ds1.Cor_Node]
You basically have a typo. In (FLNode:dscor), "FLNode" is being used a a variable name instead of as a label.
To fix this, you need to assign a variable name (say, x) to the node, make sure FLNode is specified to be a label (by putting a : in front of it), and then use x in the result. Like so:
MATCH (:dscor)-[ds1:sem1dsrelation{Name:'Semester1',Cor_Name:'Data Science'}`]-(x:FLNode:dscor)
RETURN DISTINCT [x.Name_F,ds1.Cor_Node];
I’m using Rails 4.2.7. I have an array of my model objects and currently I’m iterating through that array to find matching entries in the database based on a field my each object …
my_object_times.each_with_index do |my_object_time, index|
found_my_object_time = MyObjectTime.find_by_my_object_id_and_overall_rank(my_object_id, my_object_time.overall_rank)
My question is, how can I rewrite the above to run one query instead of N queries, if N is the size of the array. What I wanted was to force my underlying database (PostGres 9.5) to do a “IF VALUE IN (…)” type of query but I’m not sure how to extract all the attributes from my array and then pass them in appropriately to a query.
I would do something like this:
found_my_object_times = MyObjectTime.where(
object_id: my_object_id,
overall_rank: my_object_times.map(&:overall_rank)
)
I'd like to make a cypher query that generates a specific json output. Part of this output includes an object with a dynamic amount of keys relative to the children of a parent node:
{
...
"parent_keystring" : {
child_node_one.name : child_node_one.foo
child_node_two.name : child_node_two.foo
child_node_three.name : child_node_three.foo
child_node_four.name : child_node_four.foo
child_node_five.name : child_node_five.foo
}
}
I've tried to create a cypher query but I do not believe I am close to achieving the desired output mentioned above:
MATCH (n)-[relone:SPECIFIC_RELATIONSHIP]->(child_node)
WHERE n.id='839930493049039430'
RETURN n.id AS id,
n.name AS name,
labels(n)[0] AS type,
{
COLLECT({
child.name : children.foo
}) AS rel_two_representation
} AS parent_keystring
I had planned for children.foo to be a count of how many occurrences of each particular relationship/child of the parent. Is there a way to make use of the reduce function? Where a report would generate based on analyzing the array proposed below? ie report would be a json object where each key is a distinct RELATIONSHIP and the property value would be the amount of times that relationship stems from the parent node?
Thank you greatly in advance for guidance you can offer.
I'm not sure that Cypher will let you use a variable to determine an object's key. Would using an Array work for you?
COLLECT([child.name, children.foo]) AS rel_two_representation
I think, Neo4j Server API output by itself should be considered as any database output (like MySQL). Even if it is possible to achieve, with default functionality, desired output - it is not natural way for database.
Probably you should look into creating your own server plugin. This allows you to implement any custom logic, with desired output.
I have nodes within a the graph with property pathway storing an array of of values ranging from
path:ko00030
path:ko00010
.
.
path:koXXXXX
As an example, (i'm going to post in the batch import format:https://github.com/jexp/batch-import/tree/20)
ko:string:koid name definition l:label pathway:string_array pathway.name:string_array
ko:K00001 E1.1.1.1, adh alcohol dehydrogenase [EC:1.1.1.1] ko path:ko00010|path:ko00071|path:ko00350|path:ko00625|path:ko00626|path:ko00641|path:ko00830
the subsequent nodes might have a different combination of pathway values.
How do i query using CYPHER to retrieve all nodes with path:ko00010 in pathway
the closest i've gotten is using the solution provided for a different problem:
How to check array property in neo4j?
match (n:ko)--cpd
Where has(n.pathway) and all ( m in n.pathway where m in ["path:ko00010"])
return n,cpd;
but here only nodes with pathways matching exactly to the list provided are returned.
ie. if i were to query path:ko00010 like in the example above, I'll only be able to retrieve nodes holding path:ko00010 as the only element in the pathway property and not nodes containing path:ko00010 as well as other path:koXXXXX
In your query the extension of the predicate ALL is all the values in the property array, meaning that your query will only return those cases where every value in the pathway property array are found in the literal array ["path:ko00010"]. If I understand you right you want the opposite, you want to test that all values in the literal array ["path:ko00010"] are found in the property array pathway. If that's indeed what you want you can just switch their places, your WHERE clause will then be
WHERE HAS(n.pathway) AND ALL (m IN ["path:ko00010"] WHERE m IN n.pathway)
It is not strictly correct to say that your query only matches cases where the array you ask for and the property array are exactly the same. You could have had more than one value in the literal array, something like ["path:ko00010","path:ko00020"], and nodes with only one one of those values in their pathway array would also have matched–as long as all values in the property array could be found in the literal array. Conversely, with the altered WHERE filter that I've suggested, the query will match any node that has all of the values of the literal array in their pathway property.
If you want to filter the matched patterns with an array of values where all of them have to be present, this is good. In your example you only use one value, however, and for those queries there is no reason to use an array and the ALL predicate. You can simply do
WHERE HAS(n.pathway) and "path:ko00010" IN n.pathway
If in some context you want to include results where any of a set of values are found in the pathway property array you can just switch from ALL to ANY
WHERE HAS(n.pathway) AND ANY (m IN ["path:ko00010","path:ko00020"] WHERE m IN n.pathway)
Also, you probably don't need to check for the presence of the pathway property, unless you have some special use for it you should be fine without the HAS(n.pathway).
And once you've got the queries working right, try to switch out literal strings and arrays for parameters!
WHERE {value} IN n.pathway
// or
WHERE ALL (m IN {value_array} WHERE m IN n.pathway)
// or
WHERE ANY (m IN {value_array} WHERE m IN n.pathway)