Skip to content

Insert Data

Add data to DataJoint tables.

Single Row

Subject.insert1({
    'subject_id': 'M001',
    'species': 'Mus musculus',
    'date_of_birth': '2026-01-15',
    'sex': 'M'
})

Multiple Rows

Subject.insert([
    {'subject_id': 'M001', 'species': 'Mus musculus', 'date_of_birth': '2026-01-15', 'sex': 'M'},
    {'subject_id': 'M002', 'species': 'Mus musculus', 'date_of_birth': '2026-02-01', 'sex': 'F'},
    {'subject_id': 'M003', 'species': 'Mus musculus', 'date_of_birth': '2026-02-15', 'sex': 'M'},
])

From pandas DataFrame

import pandas as pd

df = pd.DataFrame({
    'subject_id': ['M004', 'M005'],
    'species': ['Mus musculus', 'Mus musculus'],
    'date_of_birth': ['2026-03-01', '2026-03-15'],
    'sex': ['F', 'M']
})

Subject.insert(df)

Handle Duplicates

# Skip rows with existing primary keys
Subject.insert(rows, skip_duplicates=True)

# Replace existing rows (use sparingly—breaks immutability)
Subject.insert(rows, replace=True)

Ignore Extra Fields

# Ignore fields not in the table definition
Subject.insert(rows, ignore_extra_fields=True)

What Not to Insert

The sections above target Manual tables — the tier whose rows are inserted directly, from outside the DataJoint pipeline (whether entered by hand through a form or GUI, or loaded by an automated ingestion tool). Other tiers get their rows a different way, and inserting into them directly breaks reproducibility:

  • Computed and Imported tables — their rows are produced only by make() through populate(); a direct insert is rejected at runtime. To change a result, delete and recompute rather than editing it by hand. See the make() reproducibility contract.
  • Lookup tables — their rows live in the table's contents in the definition code, versioned and redeployed through your normal review process, not inserted at runtime. If you find yourself inserting into a "Lookup" table from application code, make it a dj.Manual table instead. See Manual or Lookup?.

Two more rules keep inserts consistent:

  • Insert parents before children. A foreign key requires the referenced parent row to exist first, so insert upstream tables before the tables that depend on them.
  • Don't open a transaction inside make(). populate() already wraps each make() call in a transaction, so its inserts are atomic; the with schema.connection.transaction: pattern shown next is for grouping inserts in Manual code — never inside make(). See the computation model.

Master-Part Tables

Use a transaction to maintain compositional integrity:

with schema.connection.transaction:
    Session.insert1({
        'subject_id': 'M001',
        'session_idx': 1,
        'session_date': '2026-01-20'
    })
    Session.Trial.insert([
        {'subject_id': 'M001', 'session_idx': 1, 'trial_idx': 1, 'outcome': 'hit', 'reaction_time': 0.35},
        {'subject_id': 'M001', 'session_idx': 1, 'trial_idx': 2, 'outcome': 'miss', 'reaction_time': 0.82},
    ])

Insert from Query

# Copy data from another table or query result
NewTable.insert(OldTable & 'condition')

# With projection
NewTable.insert(OldTable.proj('attr1', 'attr2', new_name='old_name'))

Validate Before Insert

result = Subject.validate(rows)

if result:
    Subject.insert(rows)
else:
    print("Validation errors:")
    for error in result.errors:
        print(f"  {error}")

Insert with Blobs

import numpy as np

data = np.random.randn(100, 100)

ImageData.insert1({
    'image_id': 1,
    'pixel_data': data  # Automatically serialized
})

For multi-GB arrays, Zarr stores, HDF5 files, or any object too large to hold in memory before insert, use Staged Insert instead — it writes directly to object storage and commits the row atomically.

Insert Options Summary

Option Default Description
skip_duplicates False Skip rows with existing keys
replace False Replace existing rows
ignore_extra_fields False Ignore unknown fields

Best Practices

Batch inserts for performance

# Good: Single insert call
Subject.insert(all_rows)

# Slow: Loop of insert1 calls
for row in all_rows:
    Subject.insert1(row)
with schema.connection.transaction:
    Parent.insert1(parent_row)
    Child.insert(child_rows)

Validate before bulk inserts

if Subject.validate(rows):
    Subject.insert(rows)

See Also