For AI agents: the complete documentation index is available at https://silt-db.dev/llms.txt, the full documentation bundle is available at https://silt-db.dev/llms-full.txt, and this page is available as Markdown at https://silt-db.dev/reference/updates.md.

SQL updates

collection.updateOne(filter, update, options) and updateMany run document selection and mutation inside SQLite. JavaScript supplies bound JSON literals and returns result metadata. No update operator calls a JavaScript SQLite function or iterates over persisted documents in JavaScript.

Update a document or matching array elements

await db
  .collection('orders')
  .updateOne(
    { _id: 'order-1' },
    { $inc: { revision: 1 }, $set: { 'items.$[item].packed': true } },
    { arrayFilters: [{ 'item.quantity': { $gt: 0 } }] },
  );

upsert: true inserts when nothing matches. It seeds supported equality predicates from the filter, including dotted paths and $and, before applying the update. Conflicting equality paths fail. Replacement upserts retain an equality-filter _id and reject a conflicting replacement ID. See the database reference for result fields.

insertMany and updateMany are atomic across the Silt operation. MongoDB ordinary batches can retain earlier successful writes, so this is a deliberate compatibility difference.

Implemented operators

FamilySupported behavior
$set, $unsetExact value replacement including objects/null; dotted paths; missing-parent construction; array element unset becomes null.
$inc, $mulNumeric fields, missing-field initialization, numeric type checks, finite-result checks.
$min, $maxNative SQL BSON-style ordering over the JSON domain, including ordered objects and nested arrays.
$renameMove/replace fields through nested objects; missing source no-op; rejects traversal through arrays.
$setOnInsertApplied only to synthesized upsert documents; still participates in path-conflict validation.
$pushSingle values and $each; positive/negative $position; $sort on complete values or multiple document fields; positive/negative/zero $slice; modifier processing order matches MongoDB.
$addToSetWhole-value equality; each-input deduplication; preserves existing duplicates and object field-order distinctions.
$pop, $pull, $pullAllEndpoint removal, query-based removal, whole-value equality removal; missing-array no-op; nonarray error.
$bitand, or, xor; missing-field zero initialization; safe integer operands and integral safe numeric fields (including integral results of earlier arithmetic).
Positional paths$[], $[identifier], compound array filters and nested positional arrays. Filters read the original document even when several fields are updated.
Numeric array pathsExplicit indices, leading zeros, and null padding when extending an array. Numeric components remain literal keys when the parent is an object.
Update pipelines$set, $addFields, $unset, $project, $replaceRoot, $replaceWith, using the aggregation compiler. Fields within a stage read the same input document.

An existing _id must be preserved. Setting it to an equal value is allowed; $rename involving _id is rejected. Pipeline updates that omit _id implicitly restore its original value, as MongoDB does.

Subqueries bind intermediate values once. Array mutations use json_each and ordered JSON aggregation. Native SQL guards abort invalid per-document transformations; storage wraps multi-document updates in a transaction, so an error rolls back the operation.

Boundaries and costs

  • Input and stored values use the project's JSON domain. BSON dates, ObjectId, decimal, binary, and nonfinite numbers are not supported. Consequently $currentDate is unavailable.
  • Legacy query-bound positional $ is explicitly rejected; use $[] or filtered $[identifier].
  • Different positional identifiers, or differently spelled numeric components, whose normalized update paths could overlap are explicitly rejected. This conservative check also rejects some disjoint-filter updates that MongoDB can execute. Identical selectors on different child fields are supported.
  • MongoDB-specific error codes/messages are not reproduced. Some document-dependent validation errors surface as SQLite malformed JSON; the operation still rolls back.
  • Compound $push.$sort uses native pairwise ranking to preserve value-order semantics. It is quadratic in the updated array length; it is intended for modest arrays, not as an indexed collection-sort substitute.
  • Very large explicit array indices materialize the required null padding in SQLite and can be expensive. Large/deep statements remain subject to SQLite's compilation and nesting limits.
  • modifiedCount counts final JSON changes. MongoDB reports 1 for a pipeline that removes _id and implicitly restores it even when the final document is identical; Silt reports 0 in that narrow case.
  • Full MongoDB update parity is not claimed. Options other than upsert and arrayFilters, unspecified operators, and unsupported aggregation expressions fail explicitly.

Verification

node --test test/update.test.js runs focused public API tests for update values, path construction, arrays, modifiers, input errors, rollback, metadata and upsert.

MONGODB_URI=... node --test test/mongo-update.test.js runs the same supported cases and rejection cases against an isolated database on a real MongoDB server. It is skipped without an explicit URI. The measured reference run used MongoDB 8.0.29, not the 8.3 target. The suite checks final documents and update counts, with the explicit _id pipeline-count exception above. Nonfinite arithmetic rejection is tested locally because MongoDB's BSON domain permits infinities.

The fixtures are authored for this implementation and include semantics discovered through real MongoDB execution, such as the distinction between $pull: 1 and $pull: { $eq: 1 } on nested arrays, and $push treating a dollar-prefixed object as a literal when $each is absent.