Skip to content

Row operations (DML)

Operations that write rows: insert, update, merge, delete, move, adopt and batch. The overview lists every operation by kind. The MCP server, datanotes mcp, offers each operation as an MCP tool of the same name, and engineTools() of datanotes/mcp gives the same definitions to your own MCP server. DatanotesClient.call(name, args) runs one from code. Over HTTP each one is POST /datanotes/operations/<name>/, with its arguments as the JSON body: the HTTP API reference lists them.

Every write is validated. Writes to rows and to the schema are journaled and undone with undo_migration; configure_database, the webhook operations, vacuum_table and sync_semantic_index are not journaled.

Insert Row · write

Insert a row (new note). Values are validated against the columns; the note path comes from the table’s path/filename patterns (e.g. an event logged today about last night lands in last night’s day folder when you set occurred_at to last night). body is the note text. Generated / identity columns are computed (do not pass them); CHECK constraints are enforced. Returns migration_id (undo) and the created path in planned_creates. body links the notes it mentions by name, at their first mention (automatic links; off with autolink: false or the database’s autolink setting). links_added lists the links made; ambiguous_mentions lists the mentions left as text with the notes they may name: read those, then link the right one with update_row and autolink: false, or leave the text.

Examples: Catalogs, schemas and the database, Tables, Columns and types, Bases, Relations and hierarchies, Validation, CHECK constraints, Write and move rows, Automatic links, Batch writes, Import existing notes, Journal and undo, Table history and time travel, Change data feed, Restore a table or the database.

Parameter Type Required Default Description
table string yes
values object yes
body string \ null null
path string \ null null
dry_run boolean false
autolink boolean \ null null

Update Row · destructive write

Update exactly ONE row, addressed by its id (the system UUID) or its path; refused when the row does not exist (or id and path disagree). Same validation, journal and history as update_rows.

  • set / unset: columns to set or remove.
  • body: replace the whole note body; or edit it keeping the rest: body_sections {"History": "…"} replaces the text under that heading (any level, up to the next heading of the same level; added as ## History when missing), body_prepend / body_append add text before / after.
  • expect: compare-and-set — {"status": "open"} writes only if the row still has those values (a person may have changed it since you read it); otherwise refused, nothing written.
  • autolink: the text written links the notes it mentions by name, at their first mention (off with autolink: false or the database’s setting). links_added lists the links made; ambiguous_mentions the mentions left as text with the notes they may name: read those, then link the right one with update_row and autolink: false, or leave the text.

Examples: Columns and types, Bases, Relations and hierarchies, CHECK constraints, Hand edits, Write and move rows, Automatic links, Batch writes, Journal and undo, Table history and time travel, Change data feed, Restore a table or the database.

Parameter Type Required Default Description
table string yes
id string \ null null
path string \ null null
set object \ null null
unset string[] \ null null
body string \ null null
body_sections object \ null null
body_prepend string \ null null
expect object \ null null
body_append string \ null null
dry_run boolean false
autolink boolean \ null null

Update Rows · destructive write

Update every row matching where (required: {} is every row). where: keys AND-ed; values are equality or operators eq, ne, gt, gte, lt, lte, in, contains, icontains (case/accent-insensitive, also inside lists — use it for names and aliases), exists, within (a hierarchy link: that row and everything below); combine with or / and / not (nestable); path is a pseudo-column. A dotted key follows a link column: {"project.area": "[[Work]]"} matches rows whose project links a row with that area. set sets, unset removes; all rows are validated first. expect_count: refuse unless exactly that many match. One row, or its text: update_row.

Examples: Write and move rows.

Parameter Type Required Default Description
table string yes
where object yes The rows to change; {} is every row of the table.
set object \ null null
unset string[] \ null null
dry_run boolean false
expect_count integer \ null null

Merge Rows · destructive write

MERGE (upsert) rows into table by the key columns on (e.g. ["occurred_at"] or ["id"]): a row matching an existing one updates it (when_matched: “update” default or “ignore”), the others are inserted (when_not_matched: “insert” default or “ignore”). Date-times are compared after completion with the database time zone. A source key matching several rows, or repeated, is a conflict. One journaled, undoable operation.

Examples: Write and move rows.

Parameter Type Required Default Description
table string yes
on string[] yes
rows object[] yes
when_matched "update" \ "ignore" \ null
when_not_matched "insert" \ "ignore" \ null
dry_run boolean false

Delete Rows · destructive write

Delete rows matching where. mode: “archive” (default, move to the table’s archive folder) or “delete” (trash; content journaled for undo). on_referenced: “restrict” (default, refuse rows other notes link to), “set_null” (clear front matter links to them) or “ignore” (the links stay, to no row: an archived row is gone as a trashed one, so check_table reports them as broken_link and new links to it are refused). where is required: {} deletes every row.

Examples: Relations and hierarchies, Write and move rows, Table history and time travel.

Parameter Type Required Default Description
table string yes
where object yes The rows to change; {} is every row of the table.
mode "archive" \ "delete" \ null
on_referenced "restrict" \ "set_null" \ "ignore" \ null
dry_run boolean false

Move Rows · destructive write

Move rows matching where (required: {} is every row) to another table (e.g. split a domain out of log into its own table): sets each row’s table to the destination, applies rename ({"metric_distance_km": "distance_km"}), set and drop, adds the destination’s missing dense fields, and validates every row against the destination first. Keys unknown to the destination are reported, never dropped silently — rename or drop them explicitly. relocate: true also moves the files to the destination table’s folder (named by its filename pattern); by default rows stay where they are, as rows already in folders of their own usually do (adopt_rows, for notes that are no rows yet, moves them by default). Refused while rows staying behind link to a moved row through a column whose ref is the source table (the conflicts name them): change those links first. Undo with undo_migration.

Examples: Write and move rows.

Parameter Type Required Default Description
table string yes
to_table string yes
where object yes The rows to change; {} is every row of the table.
rename object \ null null
set object \ null null
drop string[] \ null null
relocate boolean false
dry_run boolean false

Adopt Rows · destructive write

Turn existing notes (not rows of any table yet) into rows of table, keeping their body and links: rename keys ({"data": "occurred_at"}), set for all, per_row values by note path ({"Home/x.md": {"zone": "[[Kitchen]]"}}), drop keys the table does not have. Every note gets table and a system id; with relocate (default true, unlike move_rows: notes become rows where the table keeps its rows) it moves to the table’s folder, named by its filename pattern (links to it are rewritten). All notes are validated first (as rows of table, so notes of the same call may link to one another): unknown keys and bad values are listed and nothing is written. Run with dry_run first; undo with undo_migration. Many notes: adopt them in calls of about 1,000 paths each, so a stop or a crash interrupts less (each call is one journal entry).

Examples: Import existing notes.

Parameter Type Required Default Description
table string yes
paths string[] yes
rename object \ null null
set object \ null null
per_row object \ null null
drop string[] \ null null
relocate boolean true
dry_run boolean false

Batch · destructive write

Several writes that succeed or fail together. operations: [{"op": ..., ...arguments}] where op is a row operation (insert_row, update_row, update_rows, delete_rows, merge_rows, move_rows, adopt_rows, recompute_columns, align_relations, restore_table) or a DDL op (create_table, add_column, alter_column, …), with the same arguments as the operation (an unknown one refuses the batch) (e.g. values for insert_row, set for update_row / update_rows). They run in order, each seeing the previous ones; if one is refused, the ones already applied are undone (rolled_back). Returns steps (per operation, each with its result, where ambiguous_mentions is as in insert_row) and migration_id: undo_migration on it reverts the whole batch. Use it when a change spans several rows (create an event and update the people in it). dry_run checks each operation against the current data only.

The schema changes only through operations like this one: never edit metastore.yaml by hand (no validation, no undo).

Examples: Views, Relations and hierarchies, CHECK constraints, Batch writes, Restore a table or the database.

Parameter Type Required Default Description
operations object[] yes
summary string \ null null
dry_run boolean false

Align Relations · destructive write

Add the reciprocal links missing on a table’s inverse link columns (e.g. Alice lists Carol in friends but Carol does not list Alice). Run it after declaring inverse on existing data; check_table reports such rows (code inverse). Single-value links already pointing elsewhere are conflicts (nothing written). The links it adds are checked like other writes (CHECKs that follow links, ref_where / ref_by). Writes through the tools already keep both sides in step.

Examples: Relations and hierarchies.

Parameter Type Required Default Description
table string yes
paths string[] \ null null
dry_run boolean false

Recompute Columns · destructive write

Bring generated and identity columns up to date (all rows, or only paths), e.g. after rows were edited by hand (an editor, git, sync) or a generated expression changed with alter_column. Also gives rows without an id a new one, and a duplicated note (same id as an older row) a new id. new_ids=true regenerates every id in scope (new ones on every call): only on the user’s explicit request. check_table reports stale values with code generated. No-op when nothing is stale; otherwise journaled (undo_migration) and a RECOMPUTE version in the table’s history.

Examples: Hand edits.

Parameter Type Required Default Description
table string yes
paths string[] \ null null
new_ids boolean false
dry_run boolean false