User Guide

Everything you need to install, configure, and build with Montycat — from getting started to governance, advanced operations, and security.

Montycat allows updating a single record by specifying its key (either system-generated or custom) and modifying specific fields, including complex types like pointers and timestamps.
The update operation is atomic and ensures data consistency. Nested objects are merged recursively, so omitted sibling fields are retained. Arrays, scalar values, and null replace the existing value.
If the provided values match the existing record, no changes are applied, and a no_changes_detected response is returned.

from keyspaces import Employees, Departments #keyspaces.py
from schemas import EmployeesSchema
from montycat import Pointer, Timestamp

value = EmployeesSchema(
    username = "Name",
    location = "Location",
    age = 21,
    department=Pointer(Departments, '128345335674100726154823618391811195396'), # pass previously returned key,
    dateHired=Timestamp(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
).serialize()

res1 = await Employees.insert_value(value)

# {"status": True, "payload": "128222336824100726154851618391811195396", "error": None}

res2 = await Employees.update_value(
    key="128222336824100726154851618391811195396",
    age=34,
    department=Pointer(Departments, '128345335333100726154823618391811195454'),
    dateHired=Timestamp(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
)

# {status: True, payload: None, error: None}
# or if no changes detected:
# {
#   "status": False,
#   "payload": {"no_changes": "128222336824100726154851618391811195396"},
#   "error": "Error Text"
# }

Montycat supports updating records using custom keys, which follow the same logic as system-generated keys but allow user-defined identifiers.
Custom keys provide flexibility for user-defined identifiers while maintaining the same update functionality as system-generated keys.
The operation is atomic and supports all schema-defined fields.

from keyspaces import Employees, Departments #keyspaces.py
from schemas import EmployeesSchema
from montycat import Pointer, Timestamp

value = EmployeesSchema(
    username = "Name",
    location = "Location",
    age = 21,
    department=Pointer(Departments, '128345335674100726154823618391811195396'), # pass previously returned key,
    dateHired=Timestamp(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
).serialize()

res1 = await Employees.insert_custom_key_value(custom_key="myCustomKey" value=value)

res2 = await Employees.update_value(
    custom_key="myCustomKey",
    age=34,
    department=Pointer(Departments, '128345335333100726154823618391811195454'),
    dateHired=Timestamp(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
)

# {status: True, payload: None, error: None}
# or if no changes detected:
# {
#   "status": False,
#   "payload": {"no_changes": "112424342341342"},
#   "error": "Error Text"
# }

Montycat supports bulk updates, allowing multiple records (with both regular and custom keys) to be updated in a single operation for efficiency.
Bulk updates improve performance by processing multiple updates in a single transaction.
Each item uses the same recursive object-merge rules as a single update; it does not replace the complete stored document.
The operation supports partial success, with detailed feedback on failed or unchanged keys.
Both regular and custom keys can be combined in a single bulk update.

from keyspaces import Employees #keyspaces.py

updates_regular_keys = {
    "128345335333100726154823618391811195454": {"age": 34, "username": "John"},
    "128222336824100726154851618391811195396": {"age": 28, "username": "Anna"}
}

updates_custom_keys = {
    "myFirstCustomKey": {"age": 39, "username": "Mary"},
    "mySecondCustomKey": {"age": 33, "username": "Alex"}
}

res2 = await Employees.update_bulk(bulk_keys_values=updates_regular_keys, bulk_custom_keys_values=updates_custom_keys)

# {"status": True, "payload": None, "error": None}

# or if all of updates failed: {"status": False, "payload": None, "error": "Error Text"}

# or if some of updates failed:
# {
#  "status": False,
#  "payload": {"failed": ["128222336824100726154851618391811195396"]},
#  "error": "Error Text"
# }

# or if no changes detected:
# {
#  "status": False,
#  "payload": {"no_changes": ["128222336824100726154851618391811195396"]},
#  "error": None
# }