Cypher return structured map

is it possible to return an object of objects (each key containing an object)?

what I want to achieve:

 {
     a1 : { name: "bob", age: 45 }, 
     a2 : { name: "toby", age: 27 }
 }

or

 [
   a1 : { name: "bob", age: 45 }, 
   a2 : { name: "toby", age: 27 }
 ]

my statement:

MATCH (n:User)
WITH n.id AS key, {name:n.name, age:n.age}AS value
RETURN collect({key:value})

You are really really close. I think all you need is apoc.map.fromPairs which takes an array of key value pairs and turns them into a map. For example, if you have data like this:

RETURN apoc.map.fromPairs([ ["a", "b"], ["c", "d"] ])

Then you get:

{
  "a": "b",
  "c": "d"
}

So your "values" are nested maps, but that's no problem. If you change your query to this:

match (n:User) 
with n.id as key, { name: n.name, age: n.age } as value 
return apoc.map.fromPairs(collect([key, value]));

I think you'll get what you want.

Note that you can't do this:

{ key: value }

Because in this case cypher interprets "key" as literally the text key, not as the content of whatever that variable is.

3 Likes

@david_allen thanks for the above solution mate, much appreciated. I've tried to adopt it to my problem but am turning in circles and it is driving me mad ... would you please take a quick look at the below and let me know what I'm doing wrong?

Desired output ...

{
  "JobWords": {
    {
      "IdInterface": "leader",
      "NameInterfaceLower": "leader",
      "NameInterfaceOriginal": null,
      "IdInterfaceTag": "job+word_leader"
    },
    {
      "IdInterface": "founder",
      "NameInterfaceLower": "founder",
      "NameInterfaceOriginal": null,
      "IdInterfaceTag": "job+word_founder"
    },
    {
      "IdInterface": "marketing",
      "NameInterfaceLower": "marketing",
      "NameInterfaceOriginal": null,
      "IdInterfaceTag": "job+word_marketing"
    },
    {
      "IdInterface": "measurement",
      "NameInterfaceLower": "measurement",
      "NameInterfaceOriginal": null,
      "IdInterfaceTag": "job+word_measurement"
    }
  }
}

But the Cypher I am using ...

MATCH (Employee:Employee{IdObject:'xyz'}) 
WITH Employee 

OPTIONAL MATCH (Employee)-[:LINKED_TO]->(:EmailAddress:Master)<-[:CONTAINED_IN|CONNECTED_TO]-(n:JobWord) 
WHERE NOT n:Exclude 
WITH Employee, n.IdUnique as key, {IdInterface: n.IdInterface, NameInterfaceLower: n.NameInterfaceLower, NameInterfaceOriginal: n.NameInterfaceOriginal, IdInterfaceTag: n.IdInterfaceTag} as value 
WITH Employee, apoc.map.fromPairs(collect([key, value])) as job_words 

RETURN 
Employee {

    JobWords: job_words
}

Only ever returns ...

{
  "JobWords": {
    "3e9ce5c6-6344-4cff-a80f-d4f7708e8e26": {
      "IdInterface": "leader",
      "NameInterfaceLower": "leader",
      "NameInterfaceOriginal": null,
      "IdInterfaceTag": "job+word_leader"
    },
    "862ce5d8-651c-424b-b0c9-313c500ea266": {
      "IdInterface": "founder",
      "NameInterfaceLower": "founder",
      "NameInterfaceOriginal": null,
      "IdInterfaceTag": "job+word_founder"
    },
    "4d1a76d7-44ba-462f-847b-5118599532bf": {
      "IdInterface": "marketing",
      "NameInterfaceLower": "marketing",
      "NameInterfaceOriginal": null,
      "IdInterfaceTag": "job+word_marketing"
    },
    "373d5ec0-085b-4202-9631-a3c4585dd45c": {
      "IdInterface": "measurement",
      "NameInterfaceLower": "measurement",
      "NameInterfaceOriginal": null,
      "IdInterfaceTag": "job+word_measurement"
    }
  }
}

I've tried everything to get a list from just pairs without the nested part but no luck :( I must be missing something super obvious and simply cannot see it ...