OMGDB DOCS
// Querying

Update Operators

Reference for the OMGDB update operators ($set, $unset, $inc, $mul, $min, $max, $rename, and array operators) applied through the agent-safe mutation flow.


Update operators describe how to mutate matched documents. They mirror MongoDB’s update syntax: an update spec is a JSON object whose top-level keys are operators ($set, $inc, $push, …), and each operator’s value is an object mapping field names to arguments. Operators are applied in the order they appear in the spec.

Updates are never applied blindly. They run through the agent-safe mutation flow — you plan a change (a dry run that writes nothing), apply it by token in a single transaction, then optionally roll it back to the recorded before-state. See agent mutations for the plan / apply / rollback protocol. For selecting which documents an update touches, see query operators.

Field operators

OperatorDescriptionExample
$setSets each named field to the given value, inserting it if absent.{"$set":{"role":"admin"}}
$unsetRemoves each named field. The value side of each entry is ignored.{"$unset":{"tmp":""}}
$incAdds a numeric delta to the field’s current value.{"$inc":{"age":1}}
$mulMultiplies the field’s current numeric value by a factor.{"$mul":{"n":3}}
$minSets the field only if the given value is less than the current value.{"$min":{"lo":2}}
$maxSets the field only if the given value is greater than the current value.{"$max":{"hi":9}}
$renameRemoves a field and re-inserts its value under a new name.{"$rename":{"old":"new"}}

$set

Inserts or overwrites each named field with the supplied value.

{"$set":{"role":"admin"}}

$unset

Removes each named field from the document. Removing an absent field is a no-op, and the value side of each entry ("" below) is ignored.

{"$unset":{"tmp":""}}

$inc

Adds the delta to the field’s current numeric value. An absent field is treated as 0, so $inc of 1 on a missing field results in 1.

{"$inc":{"age":1}}

Integer arithmetic uses checked addition: an i64 overflow (for example i64::MAX + 1) returns a Malformed error — $inc would overflow i64: x + y — rather than panicking or silently wrapping a corrupted value into the store. Mixed integer/float operands are promoted to f64. A non-numeric current value or delta yields $inc requires numeric values.

$inc on a field holding i64::MAX with delta 1  →  Malformed error (not wrapped)

$mul

Multiplies the field’s current numeric value by the factor.

{"$mul":{"n":3}}

Like $inc, integer multiplication is checked: an i64 overflow returns a Malformed error ($mul would overflow i64: x * y) and never wraps. Mixed integer/float operands promote to f64.

Note: Because an absent field defaults to 0, $mul on a missing field produces 0 — it does not skip the field or fall back to the factor.

$min and $max

$min writes the supplied value only when it is strictly less than the current value (or the field is absent). $max writes only when the supplied value is strictly greater (or the field is absent). Comparison uses the same ordering as the query engine.

{"$min":{"lo":2}, "$max":{"hi":9}}

If the existing value is already on the right side of the bound, it is kept unchanged. For example, $min of 99 against an existing 5 leaves 5 in place; $min of 2 against 5 lowers it to 2.

$rename

Removes the source field and re-inserts its value under the target name.

{"$rename":{"old":"new"}}

The target name must be a string, otherwise the update fails with $rename target must be a string. If the source field is absent, $rename is a no-op. It does not check whether the target already exists — an existing target is overwritten.

Array operators

OperatorDescriptionExample
$pushAppends value(s) to an array field, creating it if absent. Supports $each.{"$push":{"tags":{"$each":["c","d"]}}}
$addToSetAdds value(s) only if not already present (set semantics). Supports $each.{"$addToSet":{"tags":"a"}}
$pullRemoves every element exactly equal to the given value.{"$pull":{"tags":"a"}}
$popRemoves one element: 1 removes the last, -1 removes the first.{"$pop":{"tags":1}}

The only array modifier is $each, shared by $push and $addToSet. When the spec is an object containing $each: [...], all of those elements are used; otherwise the spec value itself is added as a single element.

$push

Appends value(s) to the array field, creating the array if the field is absent.

{"$push":{"tags":{"$each":["c","d"]}}}

With $each, every element is appended in order. Without $each, the single spec value is appended as one element. Pushing onto a field that exists but is not an array fails with array update on \field` which is not an array`.

$push {"$each":["c","d"]} onto ["a","b"]  →  ["a","b","c","d"]
$push {"xs":1} onto {}                    →  {"xs":[1]}
$push {"n":1} onto {"n":5}                →  Malformed error (n is not an array)

$addToSet

Adds value(s) to the array only if not already present. Deduplication is by full value equality.

{"$addToSet":{"tags":"a"}}

An already-present value leaves the array unchanged. With $each, each candidate is checked individually against the current array. Like $push, it creates the array if absent and errors on a non-array field.

$addToSet "a" onto ["a","b"]  →  ["a","b"]   (no-op, "a" already present)

$pull

Removes from the array field every element exactly equal to the given value.

{"$pull":{"tags":"a"}}

Matching is by full value equality.

Limitation: $pull supports only equality removal against a literal value. It does not accept a query condition such as {"$gt": 5} like MongoDB — a condition object would be compared by full value equality and almost never match. $pull is also the one array operator that silently no-ops on an absent or non-array field, instead of erroring like $push / $addToSet / $pop.

$pop

Removes a single element from the end or start of the array.

{"$pop":{"tags":1}}

The direction must be 1 (remove the last element) or -1 (remove the first); any other value fails with $pop value must be 1 (last) or -1 (first). $pop of -1 on an empty array is a safe no-op. It auto-creates an absent field as an empty array and errors on a non-array field.

$pop  1  on ["a","b"]  →  ["a"]   (removes last)
$pop -1  on ["a","b"]  →  ["b"]   (removes first)

Applying updates through the agent-safe flow

Update operators are consumed by the mutation protocol rather than written directly. A typical round trip:

  1. Plan — compute matched documents and a before/after sample without writing.
  2. Apply — execute the plan by token inside a single transaction.
  3. Rollback — restore the recorded before-state if needed.
let plan = plan_update(
    &s,
    "u",
    &obj(r#"{"name":"ada"}"#),
    &obj(r#"{"$set":{"role":"admin"},"$inc":{"age":1}}"#),
)?;
// plan reports matched == 1; the store is still unchanged (age 30, no role)

let result = apply_change(&mut s, &token)?;
// after apply: age == 31, role == "admin"

rollback(&mut s, &change_id)?; // restores age 30, role removed

Note: During planning the original _id is re-inserted into every after-document, so no update operator can ever change a document’s identifier.

See agent mutations for the full plan / apply / rollback reference, including the NDJSON plan and audit files.

Caveats

  • No dot-path or nested-field traversal. Every operator treats the field name as a literal top-level key. There is no a.b.c traversal and no positional array operators ($, $[]).
  • Limited array modifiers. Only $each is implemented. $position, $slice, and $sort are not available.
  • $currentDate is not implemented. Using it returns an unknown-operator error.
  • Operator ordering. Operators are applied in the spec’s iteration order, so the result of multiple operators touching the same field depends on that order.
  • An unrecognized operator key returns an unknown-operator error; a non-object update or a non-object operator spec returns a malformed error.

For selecting the documents an update applies to, see query operators.

Edit this page on GitHub →