Skip to main content

Import Data

When importing data into RushDB, choose the method that matches your data shape:

  • createMany — arrays of flat rows only (CSV-like). No nested objects or arrays inside items.
  • importJson — real JSON: nested, messy, arrays with nested data, or a hash-map-like top-level structure.

This page explains when to use each and shows practical examples. Keep using createMany where you already import flat arrays; use importJson for everything else.

createMany: arrays of flat rows (CSV-like) + optional upsert

Use createMany when your input is an array (or single object) of flat rows. Nested objects/arrays are not allowed.

You can also perform an upsert during creation by supplying options.mergeBy and/or options.mergeStrategy:

  • If mergeBy (array) is provided (even empty) OR mergeStrategy is provided, RushDB will attempt to match existing records.
  • If mergeBy is empty or omitted but mergeStrategy is present, all incoming property keys are used for matching.
  • mergeStrategy: 'append' (default) adds/updates incoming properties, preserving unspecified ones.
  • mergeStrategy: 'rewrite' replaces all existing properties with incoming ones (unmentioned properties are removed).
// Upsert (append) by email
await db.records.createMany({
label: 'AUTHOR',
data: authors,
options: { mergeBy: ['email'], mergeStrategy: 'append', suggestTypes: true }
})

// Rewrite (replace) by email
await db.records.createMany({
label: 'AUTHOR',
data: authors,
options: { mergeBy: ['email'], mergeStrategy: 'rewrite' }
})
import RushDB from '@rushdb/javascript-sdk';
const db = new RushDB(process.env.RUSHDB_API_KEY!);

const authors = [
{ name: 'Alice Johnson', email: 'alice@example.com', age: 30 },
{ name: 'Bob Smith', email: 'bob@example.com', age: 25 }
];

const result = await db.records.createMany({
label: 'AUTHOR',
data: authors,
options: { suggestTypes: true }
});

console.log(result.data.map(r => r.data));

Importing Data from CSV

Use importCsv when your data source is a CSV string. You can control both import options (type inference etc.), upsert behavior, and a subset of CSV parsing configuration.

import RushDB from '@rushdb/javascript-sdk';

const db = new RushDB(process.env.RUSHDB_API_KEY!);

const csv = `name,email,age\nJohn Doe,john@example.com,30\nJane Smith,jane@example.com,25`;

const customers = await db.records.importCsv({
label: 'CUSTOMER',
data: csv,
options: {
suggestTypes: true,
convertNumericValuesToNumbers: true,
returnResult: true,
mergeBy: ['email'], // upsert match key(s)
mergeStrategy: 'append' // or 'rewrite'
},
parseConfig: {
delimiter: ',',
header: true,
skipEmptyLines: true,
dynamicTyping: true
}
});

console.log(customers.data.map(c => c.data));

CSV Parse Configuration (parseConfig)

FieldTypeDefaultDescription
delimiterstring,Field delimiter
headerbooleantrueWhether first row contains headers
skipEmptyLinesboolean | "greedy"trueSkip empty (or whitespace-only when greedy) lines
dynamicTypingbooleanMirrors options.suggestTypesPapaParse numeric/boolean autodetection
quoteCharstring"Quote character
escapeCharstring"Escape character for quotes
newlinestringautoExplicit newline sequence override

If parseConfig.dynamicTyping is omitted, it inherits from options.suggestTypes.

importJson: nested or hash-map-like JSON

Use importJson when your data is nested or “messy” (arrays with nested objects, objects-within-objects, etc.), or when your top-level input is a hash map of label -> items.

importJson works in two modes:

  1. With label provided — you explicitly set the top-level label.
import RushDB from '@rushdb/javascript-sdk';
import fs from 'fs';

const db = new RushDB(process.env.RUSHDB_API_KEY!);
const data = JSON.parse(fs.readFileSync('data.json', 'utf8'));

// data.json can be nested/messy. importJson will BFS through and create
// records and relationships according to structure.
const imported = await db.records.importJson({
label: 'BLOG',
data,
options: { suggestTypes: true }
});

console.log(imported.data.length);
  1. Without label — pass a single top-level key used as the label:
const payload = {
ITEM: [
{ name: 'Sprocket', specs: { size: 'M', weight: 1.2 }, images: ['a.jpg', 'b.jpg'] },
{ name: 'Cog', specs: { size: 'S', weight: 0.7 } }
]
}

// Label is inferred as 'ITEM'
await db.records.importJson({ data: payload });

Unlabeled invalid root object — if you don’t provide label and the top level is not a single-key map, importJson throws:

await db.records.importJson({
data: {
some: 'key',
data: 1,
nested: { level: 2 }
}
});
// Error: importJson requires either an explicit label or a single top-level key to infer the label

Advanced Usage: Import Options

The importJson method accepts an optional options parameter to customize how your data is processed and stored:

const importOptions = {
suggestTypes: true,
convertNumericValuesToNumbers: true,
capitalizeLabels: false,
relationshipType: 'OWNS',
returnResult: true,
castNumberArraysToVectors: false
};

const importedUsers = await db.records.importJson({ label: 'user', data: data.users, options: importOptions })

Available Options (JSON, CSV & createMany)

OptionTypeDefaultDescription
suggestTypesBooleantrueDefault is true - Automatically infers data types for properties. Set to false to disable type inference and store all values as strings
castNumberArraysToVectorsBooleanfalseConverts numeric arrays to vector type
convertNumericValuesToNumbersBooleanfalseConverts string numbers to number type
capitalizeLabelsBooleanfalseConverts all labels to uppercase
relationshipTypeString__RUSHDB__RELATION__DEFAULT__Default relationship type between Records (nodes)
returnResultBooleanfalseReturns imported records in response
mergeByString[]undefined / []Property names used to locate existing records. If omitted and mergeStrategy provided, all incoming property keys are used. Empty array means “use all incoming keys”.
mergeStrategy'append' | 'rewrite''append'Upsert behavior: append updates/adds properties; rewrite replaces all existing properties. Providing either option triggers upsert semantics.
Default Type Inference

By default, suggestTypes is true for all import operations (importJson, importCsv, createMany). RushDB automatically infers data types from your values. To disable this and store all properties as strings, explicitly set suggestTypes: false.

Upsert Matching Rules Recap

  • Triggered when mergeStrategy or mergeBy is present in options.
  • If mergeBy omitted and mergeStrategy supplied → all incoming keys form the match fingerprint.
  • If mergeBy is an empty array ([]) → also treated as “all incoming keys”.
  • append preserves unspecified properties; rewrite removes them.

Quick rules recap

  • createMany: arrays of flat rows only. Nested objects or arrays inside items are not allowed and will cause an error — use importJson instead.
  • importJson: nested/mixed JSON. Provide label explicitly, or pass a single-key object like { LABEL: [...] } to infer the label.
  • importCsv: CSV string input with parseConfig; dynamicTyping inherits from options.suggestTypes when omitted.

How RushDB JSON Import Works

When you import data through the TypeScript SDK, RushDB applies a breadth-first search (BFS) algorithm to parse and transform your data:

  1. Data Preparation: Each record is assigned a unique UUIDv7 __id (unless provided)
  2. Type Inference: If suggestTypes is enabled, RushDB analyzes values to determine appropriate data types
  3. Graph Construction: Records become nodes in the graph database with properties and relationships
  4. Metadata Generation: Type information is stored in __proptypes for each record
  5. Storage: Data is efficiently inserted into the underlying Neo4j database

Data Structure Example

For example, importing this JSON:

{
"car": {
"make": "Tesla",
"model": "Model 3",
"engine": {
"power": 283,
"type": "electric"
}
}
}

Creates this graph structure in RushDB:

  • A car node with properties make: "Tesla" and model: "Model 3"
  • An engine node with properties power: 283 and type: "electric"
  • A relationship connecting the car to its engine
  • Property metadata nodes tracking property names and types

The TypeScript SDK abstracts this complexity, allowing you to focus on your data models.

Performance Considerations

  • For large data imports (>1,000 records), consider batching your requests in chunks
  • Setting returnResult: false is recommended for large imports to improve performance
  • For time-critical imports, pre-process your data to ensure type consistency
  • CSV imports currently read the full string; for very large files consider splitting client-side
  • Upsert on large batches may benefit from using stable unique keys in mergeBy to minimize match cost.