Skip to content

Update Operators ​

PocketDB provides a rich set of update operators for modifying document fields atomically.

Installation ​

Add PocketDB to your Cargo.toml:

toml
[dependencies]
pocketdb = "0.1"

Or via the command line:

bash
cargo add pocketdb

Creating Update Expressions ​

rust
use pocketdb::query::UpdateExpression;
use pocketdb::PocketValue;

// Single operator
let update = UpdateExpression::new()
    .set("name", PocketValue::String("Alice".into()));

// Chained operators
let update = UpdateExpression::new()
    .set("name", PocketValue::String("Alice".into()))
    .inc("age", PocketValue::Int(1))
    .push("tags", PocketValue::String("admin".into()));

$set — Set a Field Value ​

Sets the value of a field. Creates the field if it doesn't exist.

rust
use pocketdb::{filter, PocketValue};
use pocketdb::query::UpdateExpression;

users.update_one(
    &filter! { "name" => == "Alice" },
    &UpdateExpression::new().set("email", PocketValue::String("alice@new.com".into())),
)?;

$unset — Remove a Field ​

Removes a field from the document.

rust
users.update_one(
    &filter! { "name" => == "Alice" },
    &UpdateExpression::new().unset("phone"),
)?;

$inc — Increment a Numeric Field ​

Atomically increments a numeric field by the given value. Use negative values to decrement.

rust
// Increment age by 1
users.update_one(
    &filter! { "name" => == "Alice" },
    &UpdateExpression::new().inc("age", PocketValue::Int(1)),
)?;

// Decrement stock by 5
users.update_one(
    &filter! { "name" => == "Widget" },
    &UpdateExpression::new().inc("stock", PocketValue::Int(-5)),
)?;

// Increment balance by 100.50
users.update_one(
    &filter! { "name" => == "Alice" },
    &UpdateExpression::new().inc("balance", PocketValue::Float(100.50)),
)?;

$mul — Multiply a Numeric Field ​

Multiplies the value of a numeric field by the given factor.

rust
// Apply 10% price increase
users.update_one(
    &filter! { "category" => == "electronics" },
    &UpdateExpression::new().mul("price", PocketValue::Float(1.10)),
)?;

$min — Set to Minimum ​

Sets the field to the minimum of its current value and the given value.

rust
// Only update if new value is smaller
users.update_one(
    &filter! { "name" => == "Alice" },
    &UpdateExpression::new().min("score", PocketValue::Int(50)),
)?;

$max — Set to Maximum ​

Sets the field to the maximum of its current value and the given value.

rust
// Only update if new value is larger
users.update_one(
    &filter! { "name" => == "Alice" },
    &UpdateExpression::new().max("score", PocketValue::Int(100)),
)?;

$rename — Rename a Field ​

Rames a field from one name to another.

rust
users.update_one(
    &filter! { "name" => == "Alice" },
    &UpdateExpression::new().rename("username", "login_name"),
)?;

$push — Append to Array ​

Appends a value to an array field.

rust
// Add a single tag
users.update_one(
    &filter! { "name" => == "Alice" },
    &UpdateExpression::new().push("tags", PocketValue::String("admin".into())),
)?;

$addToSet — Add to Array (No Duplicates) ​

Appends a value to an array only if it doesn't already exist.

rust
users.update_one(
    &filter! { "name" => == "Alice" },
    &UpdateExpression::new().add_to_set("tags", PocketValue::String("admin".into())),
)?;
// If "admin" was already in tags, it won't be added again

$pop — Remove from Array ​

Removes the first element from an array.

rust
users.update_one(
    &filter! { "name" => == "Alice" },
    &UpdateExpression::new().pop("tags"),
)?;

$pull — Remove Matching Elements ​

Removes all elements from an array that match the given value.

rust
users.update_one(
    &filter! { "name" => == "Alice" },
    &UpdateExpression::new().pull("tags", PocketValue::String("banned".into())),
)?;

Chaining Multiple Operators ​

All operators can be chained in a single update expression:

rust
use pocketdb::{filter, PocketValue};
use pocketdb::query::UpdateExpression;

users.update_one(
    &filter! { "name" => == "Alice" },
    &UpdateExpression::new()
        .set("email", PocketValue::String("alice@new.com".into()))
        .inc("age", PocketValue::Int(1))
        .push("tags", PocketValue::String("verified".into()))
        .unset("temporary_field"),
)?;

Update One vs Update Many ​

MethodBehavior
update_oneUpdates only the first matching document
update_manyUpdates all matching documents
rust
// Update first matching document
users.update_one(&filter, &update)?;

// Update all matching documents
let count = users.update_many(&filter, &update)?;
println!("Updated {} documents", count);

Using the update! Macro ​

rust
use pocketdb::update;

let update = update! {
    "$set" => { "name" => "Bob" },
    "$inc" => { "age" => 1 }
};

users.update_one(&filter! { "name" => == "Alice" }, &update)?;

Complete Example ​

rust
use pocketdb::{Database, doc, filter, PocketValue};
use pocketdb::query::UpdateExpression;

fn main() -> pocketdb::Result<()> {
    let db = Database::open("updates_example.pdb")?;
    let products = db.collection("products")?;

    // Insert sample data
    products.insert(doc! {
        "name" => "Laptop",
        "price" => 999,
        "stock" => 50,
        "tags" => ["electronics", "computer"],
        "active" => true
    })?;

    // Set a field
    products.update_one(
        &filter! { "name" => == "Laptop" },
        &UpdateExpression::new().set("on_sale", PocketValue::Bool(true)),
    )?;

    // Increment stock
    products.update_one(
        &filter! { "name" => == "Laptop" },
        &UpdateExpression::new().inc("stock", PocketValue::Int(10)),
    )?;

    // Apply discount
    products.update_one(
        &filter! { "name" => == "Laptop" },
        &UpdateExpression::new().mul("price", PocketValue::Float(0.9)),
    )?;

    // Add tag
    products.update_one(
        &filter! { "name" => == "Laptop" },
        &UpdateExpression::new().push("tags", PocketValue::String("sale".into())),
    )?;

    // Chained update
    products.update_one(
        &filter! { "name" => == "Laptop" },
        &UpdateExpression::new()
            .set("last_updated", PocketValue::String("2024-01-01".into()))
            .inc("version", PocketValue::Int(1)),
    )?;

    // Verify
    let product = products.find_one(&filter! { "name" => == "Laptop" }).unwrap();
    println!("Price: {:?}", product.get("price"));
    println!("Stock: {:?}", product.get("stock"));
    println!("Tags: {:?}", product.get("tags"));

    Ok(())
}

Released under the MIT License. Built by Muhammad Fiaz.