Skip to main content

Import Data

RushDB accepts raw data — JSON objects, nested trees, flat arrays, or CSV — and turns it into a fully typed, linked graph. No schema definitions, no migrations, no manual relationship wiring.

How Nested Data Becomes a Graph

When you import a nested JSON object, RushDB walks the structure with a breadth-first search (BFS) algorithm. Each nested object becomes a separate record, linked to its parent by a relationship.

{
"title": "Inception",
"rating": 8.8,
"ACTOR": [
{ "name": "Leonardo DiCaprio", "country": "USA" },
{ "name": "Ken Watanabe", "country": "Japan" }
]
}

This single call produces 3 records (MOVIE + ACTOR × 2) with relationships between them, plus typed properties on each — all inferred automatically.

The ingestion pipeline

  1. Parse — BFS walk. Each nested object becomes a separate record.
  2. Type inference — Every value is classified as string, number, boolean, or datetime. A null value (or an all-null array) is treated as unset and is not stored.
  3. Label assignment — Top-level arrays and object records use the label you provide. Container objects can omit label when each top-level value is an object or an array of nested records; each top-level key becomes the label for its nested records. Nested objects derive their label from the parent key name (e.g., key "engine" → label Engine).
  4. Relationship creation — Parent → child records are linked with default relationships (__RUSHDB__RELATION__DEFAULT__).

Import Nested JSON

db.records.create_many() — pass a dict with nested structure.

db.records.create_many(
label="MOVIE",
data={
"title": "Inception",
"rating": 8.8,
"ACTOR": [
{"name": "Leonardo DiCaprio", "country": "USA"},
{"name": "Ken Watanabe", "country": "Japan"}
]
}
)
# MOVIE → ACTOR × 2: all created and linked automatically

Infer labels from top-level container keys:

db.records.create_many(
data={
"ITEM": [
{"name": "Sprocket", "weight": 1.2},
{"name": "Cog", "weight": 0.7}
],
"SUPPLIER": [
{"name": "Acme Parts"}
]
}
)
# labels inferred as 'ITEM' and 'SUPPLIER'

Import Flat Arrays

Use this for flat, row-like data (no nested objects inside items). This is the fastest path for CSV-shaped data.

db.records.create_many() — pass a list.

db.records.create_many(
label="ACTOR",
data=[
{"name": "Leonardo DiCaprio", "country": "USA"},
{"name": "Ken Watanabe", "country": "Japan"}
],
options={"suggestTypes": True}
)

Import CSV

db.records.import_csv()

with open("actors.csv") as f:
csv_content = f.read()

db.records.import_csv(
label="ACTOR",
data=csv_content,
options={"suggestTypes": True, "returnResult": False},
parse_config={"header": True, "dynamicTyping": True}
)

CSV parseConfig options

OptionDefaultDescription
delimiter,Column separator
headertrueFirst row is header
skipEmptyLinestrueIgnore blank rows ("greedy" also skips whitespace-only lines)
dynamicTypinginherits from suggestTypesAuto-convert numbers and booleans
quoteChar"Quote character
escapeChar"Escape character
newlineautoExplicit newline sequence override

Upsert by Property During Import

All import methods support native upsert-by-property via mergeBy and mergeStrategy. Use mergeBy to name the property or properties that identify an existing record. This makes repeated imports idempotent and prevents duplicate records when source data has a stable key such as email, sku, mongoId, or externalId.

Supported SDK and API surfaces:

Input shapeTypeScript SDKPython SDKREST endpoint
Flat rowsrecords.createManyrecords.create_manyPOST /api/v1/records/import/json
Nested JSONrecords.importJsonrecords.create_manyPOST /api/v1/records/import/json
CSV textrecords.importCsvrecords.import_csvPOST /api/v1/records/import/csv
Single rowrecords.upsertrecords.upsertPOST /api/v1/records
# Append — update matched records, preserve other fields
db.records.create_many(
label="ACTOR",
data=actors,
options={"mergeBy": ["name"], "mergeStrategy": "append"}
)

# Rewrite — replace all properties for matched records
db.records.import_csv(
label="ACTOR",
data=csv_content,
options={"mergeBy": ["name"], "mergeStrategy": "rewrite"}
)

Merge strategies

StrategyBehaviour
append (default)Add / update incoming fields; preserve all other existing fields
rewriteReplace all fields with incoming data; unmentioned fields are removed

mergeBy behaviour

mergeBy valueMatch behaviour
["field"]Match only on listed fields
[] or omittedMatch on all incoming property keys

Import Options

OptionTypeDefaultDescription
suggestTypesbooleantrueInfer property types automatically. Set to false to store all values as strings.
convertNumericValuesToNumbersbooleanfalseConvert string numbers to number type
capitalizeLabelsbooleanfalseUppercase all auto-derived label names
skipEmptyValuesbooleanfalseTreat empty strings ("") and empty arrays ([]) as unset — skip the property. 0 and false are kept.
relationshipTypestring__RUSHDB__RELATION__DEFAULT__Relationship type for nested links
returnResultbooleanfalseReturn created records in the response. Ignored for imports >1 000 records (summary returned instead).
mergeBystring[]undefinedProperty names to match existing records on. If omitted with mergeStrategy present, all incoming keys are used.
mergeStrategystringappendappend or rewrite. Providing either option triggers upsert semantics.

Method Quick Reference

ScenarioPythonTypeScriptREST
Flat rowscreate_many(label, data=[…])createMany({label, data:[…]})POST /import/json with array
Nested JSONcreate_many(label, data={…})importJson({label, data:{…}})POST /import/json with object
Container JSONcreate_many(data={KEY:[{…}]})importJson({data:{KEY:[{…}]}})POST /import/json without label
CSV stringimport_csv(label, data=csv)importCsv({label, data:csv})POST /import/csv

See also