Importing Data
The Importing Data domain tests how you get CSV or JSON into the graph correctly and fast: which tool fits the data volume, how batching and transactions work, and how to make loads idempotent.
LOAD CSV
LOAD CSV WITH HEADERS FROM 'file:///persons.csv' AS row reads a file from the database's import directory; a URL can be used if remote imports are enabled. Without WITH HEADERS, every row.column reference is null - a classic silent failure. Cast explicitly with toInteger(row.id), toFloat(row.score), and date(row.dob).
Making loads idempotent and fast
Create a uniqueness constraint on the merge key before loading so MERGE is an index lookup rather than a scan. MERGE the node, then SET the remaining properties, so re-running the load updates instead of duplicating. For large files, batch transactions with CALL { ... } IN TRANSACTIONS OF 10000 ROWS (the replacement for the removed USING PERIODIC COMMIT).
Worked example
CREATE CONSTRAINT person_id IF NOT EXISTS
FOR (p:Person) REQUIRE p.id IS UNIQUE;
LOAD CSV WITH HEADERS FROM 'file:///persons.csv' AS row
CALL {
WITH row
MERGE (p:Person {id: toInteger(row.id)})
SET p.name = row.name
} IN TRANSACTIONS OF 5000 ROWS;
Reasoning: the constraint blocks duplicates even if the file repeats, the index makes each MERGE cheap, and the batching bounds heap use so a million-row file does not build one giant transaction.
Bulk loading
For an initial load into an empty database, neo4j-admin database import full --nodes=... --relationships=... is far faster because it builds stores directly. It requires dedicated header columns: :ID, :LABEL, :START_ID, :END_ID, :TYPE. It cannot run against a populated database, so it is not an incremental tool.
Traps
Re-running MERGE on a non-indexed key (slow) or on a full pattern (duplicates). Expecting LOAD CSV to parse values automatically. Forgetting that the file:/// path is relative to the import directory, not the client machine.