I am trying to transform a group of nodes into a map. I am not sure if this is best done with straight Cypher or whether there is an apoc function to help. ... maybe a combination of both?
Had a chance to come back and figure it out, and -- glad to say -- figure it out I did!
MATCH (p:EntityDef)-[:HAS_A]->(n)
WITH p.name AS dynamicKey, collect(n) AS dynamicValue
WITH apoc.map.fromValues([dynamicKey, dynamicValue]) as map
WITH collect(map) as map_list
WITH map_list[0] as first,
map_list[1] as second
RETURN apoc.map.merge(first, second)
MATCH (d:EntityDef)
OPTIONAL MATCH (d)-[:HAS_A]->(p:Property)-[:OF]->(t:PropertyType)
WITH d,collect(apoc.map.merge(properties(p),{type:t.name})) as properties
RETURN collect({name:d.name,properties:properties}) as entityDefs
This query includes a PropertyType that was not in my initial example, without it we would not have needed the merge.
Looks pretty good, here's a few recommendations that use map projection to make assembling those maps a bit easier:
MATCH (d:EntityDef)
OPTIONAL MATCH (d)-[:HAS_A]->(p:Property)-[:OF]->(t:PropertyType)
WITH d,collect(p {.*, type:t.name}) as properties
RETURN collect(d {.name, properties}) as entityDefs
@andrew_bowman the feature @kevin.urban solution has that I was particularly after is that d.name is a key in the map. Using map projection we end up with
{name:"organisation",
properties:}
Hi @andrew_bowman -- Still learning here, so I have a question: Wouldn't your solution give back 2 rows of maps instead of just one map? I would test it myself, but not fully sure how @taffyb re-did their data set.
I ask because originally tinkered with some similar approaches, but found I had to use that apoc.map.merge statement to make it come out like requested:
{Person:[{name:"givenName",label:"Given Name",length:35},
{name:"surname",label:"Surname",length:35},
{name:"dob",label:"Date of Birth",format:"dd-mm-yyyy"}],
Organisation:[{name:"name",label:"Name",length:40},
{name:"established",label:"Established",format:"dd-mm-yyyy"}]
}
You're partially correct. My solution followed taffyb's approach of returning a collection of maps, so it will return a single row of a list of map values, one element per :EntityDef node.
In order to return back just a single map, instead of a list of maps, then yes you'd need to use apoc.map.merge() as in your suggested solution.
the final cypher is
MATCH (d:EntityDef)
OPTIONAL MATCH (d)-[:HAS_A]->(p:Property)-[:OF]->(t:PropertyType)
WITH d,collect(p {.*, type:t.name}) as properties
RETURN apoc.map.mergeList(collect(apoc.map.fromValues([d.name, properties]))) as entityDefs