Consolidating & Collecting into one Record - neo4j

I'm trying to write a cypher query where all related nodes are collected and returned under a key in a map:
{
name: 'chart',
CONTAINTED: [
{
name: 'id'
},
{
name: 'bloodpressure'
},
...
],
FOREIGNKEY: [
{
name: 'clientid'
}
]
}
I've attempted to do this with the following cypher query but it isn't quite right. Using the method below two records are returned rather than just one.
MATCH path=(table:tabPHI {name: 'client'})-[r]-(c)
WITH table as tab, type(r) as rel, collect(c) as col
CALL apoc.map.setKey(tab, rel, col) YIELD value as foo
return foo

MATCH (table:tabPHI {name: 'client'})-[r]-(c)
WITH table as tab, type(r) as rel, collect(c) as col
WITH tab, COLLECT(rel) AS keys, COLLECT(col) AS values
WITH keys(tab) as main_keys, [key IN keys(tab)|tab[key]] AS main_values, keys, values
CALL apoc.map.fromLists(main_keys + keys, main_values + values) YIELD value as foo
return foo
You're creating a single map for each relationship type in your query. You have to COLLECT(rel) at some point to get a single result for each tab.

Related

Return relations as child nodes in tree (Neo4j Cypher)

Is there a way to retrieve relations as child elements of a tree?
This is the basic data i have:
CREATE (:Customer {id:1, name:'Customer 1'})<-[:CREATED_BY]-(c:Category {id:1, name:'Category 1'})
WITH c as category, range(2, 7) as subCatIds
FOREACH (s IN subCatIds | CREATE (category)<-[:SUBCATEGORY_OF]-(:Category {id:s, name:'SubCategory '+s}))
WITH category, range(1, 5) as attTypeIds
FOREACH (a IN attTypeIds | CREATE (category)-[:HAS_ATTRIBUTE {name:'Attribute '+a, required: (a%2=0)}]->(:AttributeType {id:a, name:'AttributeType '+a}))
WITH category
MATCH p = (:AttributeType)<-[:HAS_ATTRIBUTE]-(category)<-[:SUBCATEGORY_OF]-(:Category)
RETURN p
So this query returns correctly the tree structure:
MATCH (:Customer {id:1})<-[:CREATED_BY]-(c:Category {id:1}),
p = (c)<-[:SUBCATEGORY_OF*0..1]-(:Category)
WITH COLLECT(p) as category
CALL apoc.convert.toTree(category) yield value
RETURN value
How do i add the relationships [:HAS_ATTRIBUTE] as child nodes to this query?
I've tried already:
MATCH (:Customer {id:1})<-[:CREATED_BY]-(c:Category {id:1}),
SubCatsP = (c)<-[:SUBCATEGORY_OF*0..1]-(:Category),
AttP = (c)-[:HAS_ATTRIBUTE]->(att:AttributeType)
WITH COLLECT(SubCatsP) as category, RELATIONSHIPS(AttP) as attributes
CALL apoc.convert.toTree(category) yield value
RETURN value, attributes
But this returns 5 records (1 for each relationship [:HAS_ATTRIBUTE]) with the Category-Subcategories tree repeated.
I expect the result to be:
{
id: 1,
name: 'Category 1',
SUBCATEGORY_OF:[
{id:2, name: 'Subcategory 2'}, ...
]
HAS_ATTRIBUTE:[
{name: 'Attribute 1', required: false, att: {name:'AttributeType 5',id:5}}, ...
<OR>
{name: 'Attribute 1', required: false, att.name:'AttributeType 5',att.id:5}, ...
]
}
Is this even possible or do you consider a better approach to perform 2 separate queries?
You can try combining the paths into a single list:
MATCH (:Customer {id:1})<-[:CREATED_BY]-(c:Category {id:1}),
SubCatsP = (c)<-[:SUBCATEGORY_OF*0..1]-(:Category),
AttP = (c)-[:HAS_ATTRIBUTE]->(att:AttributeType)
WITH COLLECT(SubCatsP) + COLLECT(AttP) as category
CALL apoc.convert.toTree(category) yield value
RETURN value

How to return all properties of a node with distinct on one property using Cypher

I am new to cypher, and I want to get data after using 'DISTINCT', but I could only get the value of 'DISTINCT' property, for example:
CREATE (n:person {name: "a", age: 22})
CREATE (n:person {name: "a", age: 23})
CREATE (n:person {name: "a", age: 24})
I want to get only one node with label "person" whose name is "a", so I try query like this
MATCH (n:person) RETURN DISTINCT n.name
This only return "a", but I want all properties and values of the node, which is {name: "a", age:22}, what should I do?
You can try this query :
MATCH (n:person)
WITH n.name, collect(n) AS persons
RETURN persons[0]
collect is an aggregate function, so in it you will have all the node aggreagted by n.name, and I return the first element.
To get just one person node with the name "a":
MATCH (n:person {name: "a"})
RETURN n
LIMIT 1;

Cypher: using OPTIONAL MATCH in combination with collect returns default item when there is none

I'm using Neo4J to retrieve a person and their skills. This is my Cypher query:
MATCH (p:Person {id: "1"})
OPTIONAL MATCH (p) -[exp:HAS_EXPERIENCE]->(s:Skill)
WITH collect(distinct {id: s.id, name: s.name}) as skills, p
RETURN p.id as id, skills
This is the result:
{
"id": "1",
"skills": [
{
"name": null,
"id": null,
}
]
}
As you can see, the list of skills contains a 'default' item. However, in this particular case the person has no skills.
Why does the result contain an array item? How to I adjust the query so that an empty array is returned?
Using Neo4J 3.1.1.
This should work:
MATCH (p:Person {id: "1"})
OPTIONAL MATCH (p)-[exp:HAS_EXPERIENCE]->(s:Skill)
RETURN p.id AS id,
CASE WHEN s IS NULL THEN [] ELSE COLLECT(distinct {id: s.id, name: s.name}) END as skills;
s would only be NULL if the OPTIONAL MATCH does not match anything.
You may wish to consider the following:
MATCH (p:Person {id: "1"})
OPTIONAL MATCH (p) -[exp:HAS_EXPERIENCE]->(s:Skill)
RETURN p {id: p.id, skills: COLLECT(distinct s {.*})}
Assuming that you wish to get all fields from the Skill. Otherwise
... collect(distinct s {id:s.id, name:s.name})

Neo4j. Create constraint to count of relationships having type "RT"?

I use this code to get paths between nodes a and b that contain two and less relations RT.
MATCH (a:Tes1 { title: "a" }),(b:Tes1 { title: "b" }), p=shortestPath((a)-[r:BT|RT*]-(b))
WITH count(type(r)='RT') as cnt
WHERE cnt < 3
RETURN p;
error:
Type mismatch: expected Relationship but was List (line 2, column 17 (offset: 111))
"WITH count(type(r)='RT') as cnt"
I know that this error means but I don't know another way.
Please, help
You cannot count a specific type of a collection, you need to filter it and get its size :
MATCH (a:Tes1 { title: "a" }),(b:Tes1 { title: "b" }), p=shortestPath((a)-[r:BT|RT*]-(b))
WITH p, filter(x IN relationships(p) WHERE type(x) = "RT") AS rtRels
WHERE size(rtRels) < 3
RETURN p;

Use EXTRACT(Keys) or other method to get a Nodes properties as key:value pairing with Cypher in Neo4j

I want to use a cypher query to return results in a format that I can use with D3. What I have below is working fine but I want to be able to include the properties of the nodes as "key:value" pairs directly after the labels are printed out. I can't explicitly code this because different nodes can have different properties e.g. I can't just add (prop1: l1.prop1, prop2: l1.prop2 .....).
MATCH (l0) -[r]-> (l1)
WHERE ID(l0) = #
RETURN
[
{
type: "node",
id: id(l0),
labels: labels(l0),
},
{
type: "node",
id: id(l1),
labels: labels(l1)
}
] as nodes,
[
{
startNodeId: ID(startNode(r)),
endNodeId: ID(endNode(r)),
relType: type(r)
}
] as relationship
I came accross this example on the forum which is close to what I want:
MATCH (n) WHERE id(n)=#
RETURN EXTRACT(key IN keys(n) | {key: key, value: n[key]})
This results in the following:
[{"key":"name","value":"Test Node 1"}]
where as I want to have just
[{"name":"Test Node 1"}]
I am using the KOA-NEO4J library so connecting to Neo4j over Bolt if that makes any difference.
Thanks a lot,
Cypher itself does not allow for dynamically creating the key of a map, however you can use the APOC function apoc.map.fromPairs to accomplish this. So your example above becomes:
MATCH (n) WHERE id(n) = #
apoc.map.fromPairs([key IN keys(n) | [key, n[key]]])
And your larger query becomes:
MATCH (l0) -[r]-> (l1)
WHERE ID(l0) = 1
RETURN
[
{
type: "node",
id: id(l0),
labels: labels(l0),
props: apoc.map.fromPairs([key IN keys(l0) | [key, l0[key]]])
},
{
type: "node",
id: id(l1),
labels: labels(l1),
props: apoc.map.fromPairs([key IN keys(l1) | [key, l1[key]]])
}
] as nodes,
[
{
startNodeId: ID(startNode(r)),
endNodeId: ID(endNode(r)),
relType: type(r)
}
] as relationship

Resources