#3674 Exporting from Neo4j
- Get link
- X
- Other Apps
#3674 Exporting from Neo4j
#3674 How do I export a JSON representation of a Neo4j knowledge graph?
1. Export Query Results as JSON (via Cypher)
You can directly return JSON-like structures in Cypher:
MATCH (n)-[r]->(m) RETURN { source: id(n), source_labels: labels(n), source_properties: properties(n), relationship: type(r), rel_properties: properties(r), target: id(m), target_labels: labels(m), target_properties: properties(m) } AS json_row;
In the Neo4j Browser or Neo4j Desktop, this will give you JSON objects per row.
In Python (with neo4j-driver) you can collect and dump them:
import json
from neo4j import GraphDatabase
driver = GraphDatabase.driver("bolt://localhost:7687", auth=("neo4j", "password"))
with driver.session() as session:
result = session.run("""
MATCH (n)-[r]->(m)
RETURN {
source: id(n),
source_labels: labels(n),
source_properties: properties(n),
relationship: type(r),
rel_properties: properties(r),
target: id(m),
target_labels: labels(m),
target_properties: properties(m)
} AS row
""")
data = [record["row"] for record in result]
with open("graph.json", "w") as f:
json.dump(data, f, indent=2)
2. APOC Export (Recommended for Whole Graphs)
If you have the APOC plugin, you can export directly:
CALL apoc.export.json.all("graph.json", {useTypes:true});
Other variations:
-
apoc.export.json.data([nodes],[rels], "graph.json", {})
-
apoc.export.json.graph(graph, "graph.json", {})
This saves the JSON file in the Neo4j import/
directory by default.
3. Browser "Export JSON"
In Neo4j Browser or Bloom, after running a query, you can click the export menu (download icon) → JSON. This is great for ad hoc exports but not for automation.
4. Python or JavaScript Custom Exporter
If you want a nested JSON structure (like {"nodes": [...], "links": [...]}
for D3.js or visualization):
with driver.session() as session:
nodes = session.run("MATCH (n) RETURN id(n) AS id, labels(n) AS labels, properties(n) AS props")
rels = session.run("MATCH (n)-[r]->(m) RETURN id(r) AS id, type(r) AS type, id(n) AS source, id(m) AS target, properties(r) AS props")
graph_json = {
"nodes": [dict(record) for record in nodes],
"links": [dict(record) for record in rels]
}
with open("graph.json", "w") as f:
json.dump(graph_json, f, indent=2)
✅ Recommendation:
-
For automation / full dumps, use APOC export.
-
For custom shapes (like D3.js or knowledge graph pipelines), use the Python/JavaScript driver method.
Do you want the JSON to be raw Neo4j data (like APOC gives) or structured for visualization / downstream use (like nodes
+ links
format)?
The HTML produces a blank canvas from a JSON file exported directly from Neo4j
A blank canvas almost always means your HTML expects a different JSON shape (or it never loads the file). Here’s a fast fix + a checklist.
Quick checklist (common causes)
-
Wrong JSON shape
Libraries like D3/vis.js typically expect:
{
"nodes": [{ "id": "n1", "label": "Person", "props": { ... } }, ...],
"links": [{ "source": "n1", "target": "n2", "type": "KNOWS", "props": { ... } }, ...]
}
APOC’s raw export is usually a flat list of records, not nodes/links
. That mismatch = blank.
-
IDs don’t match
links[].source/target
must matchnodes[].id
exactly (string vs number mismatches or using internal ids in one place and external ids in another will break the layout). -
Fetch didn’t happen
Opening HTML from disk (file://
) blocksfetch('graph.json')
. Serve files via a tiny server (e.g.,python -m http.server 8080
) and loadhttp://localhost:8080/
. -
Container has no size
If your<svg>
or<canvas>
is 0×0 (no width/height or CSS), nothing renders. -
Silent JS errors
Open DevTools → Console. Any error aboutdata.nodes
ordata.links
means (1) above.
Option A — Export D3-ready JSON directly from Neo4j
If you have APOC, run a single export that returns the exact shape your HTML needs:
CALL apoc.export.json.query( " MATCH (n) WITH collect(DISTINCT n) AS ns MATCH (n)-[r]->(m) WITH ns, collect(DISTINCT r) AS rs WITH [x IN ns | {id: toString(id(x)), labels: labels(x), props: properties(x)}] AS nodes, [x IN rs | { id: toString(id(x)), type: type(x), source: toString(id(startNode(x))), target: toString(id(endNode(x))), props: properties(x) }] AS links RETURN {nodes:nodes, links:links} AS graph ", "graph.json", {useTypes:true, stream:false} );
This writes graph.json
(usually into Neo4j’s import/
directory) with {nodes:[...], links:[...]}
.
Option B — Transform an existing APOC export into nodes/links
If you already exported raw APOC JSON (list of node/rel objects), transform it before drawing. Here’s a small browser-side transformer you can drop into your page:
<script>
async function loadGraph() {
const raw = await fetch('apoc_raw.json').then(r => r.json());
// raw could be an array of mixed entries or two arrays; normalize:
const nodes = [];
const links = [];
const nodeSeen = new Set();
for (const row of raw) {
// Heuristics for APOC shapes — adjust if your file differs:
// Node-like
if ((row.type === 'node' || row.labels) && row.properties) {
const id = String(row.id ?? row._id ?? row.elementId ?? row.properties.id ?? row.identity);
if (id && !nodeSeen.has(id)) {
nodeSeen.add(id);
nodes.push({
id,
labels: row.labels || row.label || [],
props: row.properties
});
}
}
// Relationship-like
if ((row.type === 'relationship' || row.rel || row.relationship) && row.properties) {
const rid = String(row.id ?? row._id ?? row.elementId ?? row.properties.id ?? row.identity);
const source = String(row.start ?? row.startNode ?? row.startNodeId ?? row.from);
const target = String(row.end ?? row.endNode ?? row.endNodeId ?? row.to);
links.push({
id: rid,
type: row.label || row.type || row.relationship,
source,
target,
props: row.properties
});
}
}
// Ensure that every link endpoint exists as a node
const have = new Set(nodes.map(n => n.id));
for (const k of ['source','target']) {
for (const e of links) {
if (!have.has(e[k])) {
nodes.push({ id: e[k], labels: ['Unresolved'], props: {} });
have.add(e[k]);
}
}
}
return { nodes, links };
}
</script>
Minimal, known-good D3 template (works if your JSON is {nodes,links}
)
Save this as index.html
, put graph.json
next to it, and serve via a local server:
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Graph</title>
<style>
html, body { height:100%; margin:0; }
#viz { width:100%; height:100vh; }
svg { width:100%; height:100%; display:block; }
.node circle { r:6; }
.link { stroke-opacity:0.6; }
</style>
</head>
<body>
<div id="viz"></div>
<script src="https://unpkg.com/d3@7"></script>
<script>
(async function() {
// If you used Option B, replace next line with: const data = await loadGraph();
const data = await fetch('graph.json').then(r => r.json());
// Basic validation
if (!data.nodes || !data.links) {
throw new Error('Expected {nodes:[], links:[]} in graph.json');
}
const width = document.getElementById('viz').clientWidth;
const height = document.getElementById('viz').clientHeight;
const svg = d3.select('#viz').append('svg');
const sim = d3.forceSimulation(data.nodes)
.force('link', d3.forceLink(data.links).id(d => String(d.id)).distance(60).strength(0.1))
.force('charge', d3.forceManyBody().strength(-160))
.force('center', d3.forceCenter(width/2, height/2));
const link = svg.append('g')
.attr('stroke', '#999')
.attr('class', 'link')
.selectAll('line')
.data(data.links)
.join('line');
const node = svg.append('g')
.attr('class', 'node')
.selectAll('circle')
.data(data.nodes)
.join('circle')
.attr('r', 5)
.attr('fill', '#4682b4')
.call(d3.drag()
.on('start', (event, d) => { if (!event.active) sim.alphaTarget(0.3).restart(); d.fx = d.x; d.fy = d.y; })
.on('drag', (event, d) => { d.fx = event.x; d.fy = event.y; })
.on('end', (event, d) => { if (!event.active) sim.alphaTarget(0); d.fx = null; d.fy = null; })
)
.append('title')
.text(d => (d.labels?.[0] || 'Node') + ' ' + d.id);
sim.on('tick', () => {
link
.attr('x1', d => d.source.x)
.attr('y1', d => d.source.y)
.attr('x2', d => d.target.x)
.attr('y2', d => d.target.y);
svg.selectAll('circle')
.attr('cx', d => d.x)
.attr('cy', d => d.y);
});
window.addEventListener('resize', () => {
const w = document.getElementById('viz').clientWidth;
const h = document.getElementById('viz').clientHeight;
svg.attr('width', w).attr('height', h);
sim.force('center', d3.forceCenter(w/2, h/2)).alpha(0.2).restart();
});
})();
</script>
</body>
</html>
If you prefer to build the JSON via Cypher (no post-processing)
Run this in Neo4j Browser to copy/paste the JSON result directly (or export via APOC as shown earlier):
MATCH (n) WITH collect(DISTINCT {id: toString(id(n)), labels: labels(n), props: properties(n)}) AS nodes MATCH (a)-[r]->(b) WITH nodes, collect(DISTINCT { id: toString(id(r)), type: type(r), source: toString(id(startNode(r))), target: toString(id(endNode(r))), props: properties(r) }) AS links RETURN {nodes:nodes, links:links} AS graph;
Copy the graph
value to graph.json
.
Debug fast
-
Open console: look for
Expected {nodes:[], links:[]}
orCannot read properties of undefined (reading 'x')
→ means yourlinks
don’t resolve to node IDs. -
Log shapes:
console.log(data, data.nodes?.[0], data.links?.[0])
. -
Check ID types: cast everything to
String(id(...))
in Cypher and use.id(d => String(d.id))
in D3.
If you share a tiny snippet of your current JSON (first two elements of whatever it contains), I’ll tailor the exact one-liner transform for your format.
From <https://chatgpt.com/> ChatGPT 5
- Get link
- X
- Other Apps
Comments
Post a Comment