## 15.3. Virtual Graph

This section describes procedures that create virtual graphs from Cypher queries or JSON documents.

Create a graph object (map) from information that’s passed in. It’s basic structure is: `{name:"Name",properties:{properties},nodes:[nodes],relationships:[relationships]}`

`apoc.graph.from(data,'name',{properties}) yield graph` | creates a virtual graph object for later processing it tries its best to extract the graph information from the data you pass in
`apoc.graph.fromData([nodes],[relationships],'name',{properties})` | creates a virtual graph object for later processing
`apoc.graph.fromPaths(path,'name',{properties})` | creates a virtual graph object for later processing
`apoc.graph.fromPaths([paths],'name',{properties})` | creates a virtual graph object for later processing
`apoc.graph.fromDB('name',{properties})` | creates a virtual graph object for later processing
`apoc.graph.fromCypher('statement',{params},'name',{properties})` | creates a virtual graph object for later processing
`apoc.agg.graph(element) as graph` | aggregates graph elements to a "graph" map with unique sets of "nodes" and "relationships"

Create a graph object (map) from information that’s passed in. Its basic structure is: `{name:"Name",properties:{properties},nodes:[nodes],relationships:[relationships]}`

`apoc.graph.from(data,'name',{properties}) yield graph` | creates a virtual graph object for later processing it tries its best to extract the graph information from the data you pass in
`apoc.graph.fromData([nodes],[relationships],'name',{properties})` | creates a virtual graph object for later processing
`apoc.graph.fromPaths(path,'name',{properties})` | creates a virtual graph object for later processing
`apoc.graph.fromPaths([paths],'name',{properties})` | creates a virtual graph object for later processing
`apoc.graph.fromDB('name',{properties})` | creates a virtual graph object for later processing
`apoc.graph.fromCypher('statement',{params},'name',{properties})` | creates a virtual graph object for later processing
`apoc.graph.fromDocument({json},{config})` | transform JSON documents into graph structures
`apoc.graph.validateDocument({json},{config})` | validate the JSON and returns information about required fields violations

### 15.3.1. `apoc.graph.fromDocument`

The procedure `apoc.graph.fromDocument` transforms a JSON into a graph structure. It takes two arguments:

- json, type Object: the JSON that must be transformed. Every entry must have an `id` and a `type` (name of Label), configurable via the config params. The value can be a String, or Cypher Map or List of Maps.
- config, type Map: the configuration params

Currently spatial and datetime properties are not handled yet. More advanced configuration for mapping the document is coming in future versions.

The config is composed by the following parameters:

- write, type boolean: persist the graph otherwise return a Virtual Graph, default false
- labelField, type String: the field name that became the label of the node, default type
- idField, type String: the document field name that will become the id field of the created nodes (used for node resolution when you create relationships between nodes), default id
- generateId, type boolean: in case of missing id-field value it generates an UUID for it, default true
- defaultLabel, type String: in case of missing label-field value is uses the provided default label, default is empty
- skipValidation, type boolean: in case you want skip the validation process into the `apoc.graph.fromDocument` procedure false

- mappings, type Map<String, String>: you can use a JSON path like syntax for:

  - include properties
  - defining document properties as value objects, by prepending the `@` to the property name
  - define custom/composite keys per Labels, by prepending the `!` to the property name

Following an example of configuration with mappings:

    {
        write: false,
        idField: "id",
        mappings: {
          `$`: 'Person:Reader{*,@size}'
          `$.books`: 'Book{!title, released}'
        }
    }

Lets describe the mappings:

- `$`: 'Person:Reader{*,@size}': this means that at the root object will be applied two labels `Person` and `Reader`, all properties are included and the `size` property will be transformed into a value objects as you can see no id is specified so we will consider as id the property defined into the `idField`
- `$.books`: 'Book{!title, released}': this means that at the `books` property of the root object will transformed into a node with label Book composed by two properties `title` considered as id (it’s marked with `!`) and `released` moreover the property will be connected to the parent node of type `Person:Reader` via the `BOOKS` relationship

    {
        "id": 1,
        "type": "artist",
        "name": "Genesis",
        "members": ["Tony Banks", "Mike Rutherford", "Phil Collins"],
        "years": [1967, 1998, 1999, 2000, 2006]
    }

In this case it create one `Node` with labels Artist

It also accepts list of documents:

    [{
        "id": 1,
        "type": "artist",
        "name": "Genesis",
        "members": ["Tony Banks", "Mike Rutherford", "Phil Collins"],
        "years": [1967, 1998, 1999, 2000, 2006]
    }, {
        "id": 2,
        "type": "artist",
        "name": "Daft Punk",
        "members": ["Guy-Manuel de Homem-Christo", "Thomas Bangalter."],
        "years": [1987, 1993, 1999, 2004, 2008, 2011]
    }]

In this case it create 2 `Node` with labels Artist

JSON Tree to graph:

    {
    	"id": 1,
    	"type": "artist",
    	"name": "Genesis",
    	"albums": [{
    		"type": "album",
    		"id": 1,
    		"producer": "Jonathan King",
    		"title": "From Genesis to Revelation"
    	}]
    }

In this case it will create 2 `Node`, one Artist and one Album connected to each other by the ALBUMS `Relationship`

### 15.3.2. Virtual Graph Examples

We create a dataset for our examples

    CREATE (a:Actor {name:'Tom Hanks'})-[r:ACTED_IN {roles:'Forrest'}]->(m:Movie {title:'Forrest Gump'})
    RETURN *

Virtual graph from data.

    MATCH (n)-[r]->(m) CALL apoc.graph.fromData([n,m],[r],'test',{answer:42})
    YIELD graph
    RETURN *

Virtual graph from path.

    MATCH path = (n)-[r]->(m) CALL apoc.graph.fromPath(path,'test',{answer:42})
    YIELD graph
    RETURN *

Virtual graph from paths.

    MATCH path = (n)-[r]->(m) CALL apoc.graph.fromPaths([path],'test',{answer:42})
    YIELD graph
    RETURN *

Virtual graph from DB.

    CALL apoc.graph.fromDB('test',{answer:42})
    YIELD graph
    RETURN *

Virtual graph from Cypher.

    CALL apoc.graph.fromCypher('MATCH (n)-[r]->(m) RETURN *',null,'test',{answer:42})
    YIELD graph
    RETURN *

As a result we have a virtual graph object for later processing

Virtual graph from JSON.

    CALL apoc.graph.fromDocument("{'id': 1,'type': 'artist','name':'Genesis','members': ['Tony Banks','Mike Rutherford','Phil Collins'],'years': [1967, 1998, 1999, 2000, 2006],'albums': [{'type': 'album','id': 1,'producer': 'Jonathan King','title': 'From Genesis to Revelation'}]}", {write: false})
    YIELD graph
    RETURN graph

As a result we have a virtual graph with two nodes and one relationship:

In case this json:

    {
        "id": 1,
        "type": "Person",
        "name": "Andrea",
        "sizes": {
            "weight": {
                "value": 70,
                "um": "Kg"
            },
            "height": {
                "value": 174,
                "um": "cm"
            }
        }
    }

You can manage the `sizes` property as value object so you manage it as follows:

    call apoc.graph.validateDocument(<json>, {mappings: {`$`: "Person{*,@sizes}"}})

So the procedure will create a node with the following properties:

    {
        "id": 1,
        "type": "Person",
        "name": "Andrea",
        "sizes.weight.value": 70,
        "sizes.weight.um": "Kg",
        "sizes.height.value": 174,
        "sizes.height.um": "cm"
    }

As specified you can also provide a set of value-object properties for a Label:

    call apoc.graph.validateDocument(<json>, {mappings: {`$`: "Person{*,@sizes}"}})

You can also do a pre-validation over the document with the `apoc.graph.validateDocument` procedure that will return the record with invalid data.

    call apoc.graph.validateDocument('[{"foo": "foo"}, {"bar": "bar", "id": 1, "type": "label"}, {"fooBar": "fooBar", "id": 1}]')

or

    call apoc.graph.validateDocument([{foo: "foo"}, {bar: "bar", id: 1, type: "label"}, {fooBar: "fooBar", id: 1}])

Will display the following result: