ALOS DB supports a rich query language with comparison operators, logical operators, regex, nested field access, and an aggregation pipeline.
The simplest query matches documents by exact field values:
users := db.Collection("users") // Find by exact field value user, err := users.FindOne(alosdbclient.Document{"name": "Alice"}) // Find by _id (fastest — direct hash lookup) user, err = users.FindOne(alosdbclient.Document{"_id": "abc123"}) // FindMany multiple matching documents admins, err := users.FindMany(alosdbclient.Document{"role": "admin"})
An empty query {} matches all documents:
// Return all documents in the collection all, err := users.FindMany(alosdbclient.Document{})
Multiple fields in a query are implicitly AND-ed:
// Both conditions must match results, _ := users.FindMany(alosdbclient.Document{ "role": "admin", "active": true, })
ALOS DB provides literal-value helpers that prevent query injection when untrusted input is used
in queries. Without protection, a malicious value such as {"$ne": "impossible"}
can bypass authentication checks or leak data.
// Vulnerable — user input can inject operators user, _ := users.FindOne(alosdbclient.Document{ "username": username, "password": password, })
// Safe — values are guaranteed to be treated as literals user, _ := users.FindOne(alosdbclient.Document{ "username": alosdbclient.Str(username), "password": alosdbclient.Str(password), })
| Helper | Type | Example |
|---|---|---|
alosdbclient.Str(v) |
string | "username": alosdbclient.Str(name) |
alosdbclient.Int(v) |
int | "age": alosdbclient.Int(age) |
alosdbclient.Int64(v) |
int64 | "ts": alosdbclient.Int64(timestamp) |
alosdbclient.Float(v) |
float64 | "score": alosdbclient.Float(score) |
alosdbclient.Bool(v) |
bool | "active": alosdbclient.Bool(true) |
alosdbclient.Nil() |
nil | "deleted": alosdbclient.Nil() |
alosdbclient.Time(v) |
time.Time | "created": alosdbclient.Time(t) |
alosdbclient.Bytes(v) |
[]byte | "data": alosdbclient.Bytes(b) |
alosdbclient.Arr(items...) |
[]interface{} | "tags": alosdbclient.Arr("a", "b") |
alosdbclient.Map(items...) |
Document | "meta": alosdbclient.Map("k", "v") |
// Safe array literal results, _ := users.FindMany(alosdbclient.Document{ "role": alosdbclient.Str(role), "tags": alosdbclient.Arr("verified", "premium"), }) // Safe nested map literal (rejects operator keys like "$ne") results, _ = users.FindMany(alosdbclient.Document{ "profile": alosdbclient.Map("level", "gold"), })
Important: alosdbclient.Map panics if any key starts with $,
making injection via nested maps impossible. Use it whenever you build subdocuments from
untrusted input.
Use operators inside a nested Document for richer matching:
| Operator | Meaning | Example |
|---|---|---|
$eq |
Equals | {"age": {"$eq": 30}} |
$ne |
Not equal | {"status": {"$ne": "banned"}} |
$gt |
Greater than | {"age": {"$gt": 21}} |
$gte |
Greater than or equal | {"age": {"$gte": 18}} |
$lt |
Less than | {"price": {"$lt": 100}} |
$lte |
Less than or equal | {"score": {"$lte": 50}} |
$in |
In array | {"role": {"$in": ["admin","mod"]}} |
$nin |
Not in array | {"role": {"$nin": ["banned"]}} |
// Age greater than or equal to 18 adults, _ := users.FindMany(alosdbclient.Document{ "age": alosdbclient.Document{"$gte": 18}, }) // Price between 10 and 100 (combine $gte and $lte) products, _ := db.Collection("products").FindMany(alosdbclient.Document{ "price": alosdbclient.Document{"$gte": 10, "$lte": 100}, }) // Role in a specific set staff, _ := users.FindMany(alosdbclient.Document{ "role": alosdbclient.Document{"$in": []interface{}{"admin", "moderator", "editor"}}, }) // Not equal active, _ := users.FindMany(alosdbclient.Document{ "status": alosdbclient.Document{"$ne": "deleted"}, })
Combine multiple conditions with $and and $or:
// Match either condition results, _ := users.FindMany(alosdbclient.Document{ "$or": []interface{}{ alosdbclient.Document{"role": "admin"}, alosdbclient.Document{"age": alosdbclient.Document{"$gte": 21}}, }, })
// Explicit AND (useful when querying the same field twice) results, _ := users.FindMany(alosdbclient.Document{ "$and": []interface{}{ alosdbclient.Document{"age": alosdbclient.Document{"$gte": 18}}, alosdbclient.Document{"age": alosdbclient.Document{"$lt": 65}}, }, })
Tip: You can combine multiple comparison operators on the same field
without $and:{"age": {"$gte": 18, "$lt": 65}}
// Documents that have an "email" field results, _ := users.FindMany(alosdbclient.Document{ "email": alosdbclient.Document{"$exists": true}, }) // Documents that do NOT have a "deleted_at" field results, _ = users.FindMany(alosdbclient.Document{ "deleted_at": alosdbclient.Document{"$exists": false}, })
// Names starting with "A" results, _ := users.FindMany(alosdbclient.Document{ "name": alosdbclient.Document{"$regex": "^A"}, }) // Email addresses from a specific domain results, _ = users.FindMany(alosdbclient.Document{ "email": alosdbclient.Document{"$regex": "@example\\.com$"}, })
$regex uses Go’s regexp package (RE2 syntax). Lookbehinds
and backreferences are not supported. Regex queries perform a full collection scan
— use indexed fields for high-throughput queries.
Access nested document fields with dot notation:
// Insert a document with nested fields users.InsertOne(alosdbclient.Document{ "name": "Alice", "address": alosdbclient.Document{ "city": "Sydney", "state": "NSW", "zip": "2000", }, }) // Query by nested field using dot notation results, _ := users.FindMany(alosdbclient.Document{ "address.city": "Sydney", }) // Nested fields work with operators too results, _ = users.FindMany(alosdbclient.Document{ "address.zip": alosdbclient.Document{"$gte": "2000", "$lt": "3000"}, })
Dot notation works to any depth: "a.b.c.d" accesses
doc["a"]["b"]["c"]["d"].
// Update only the "age" field, leave everything else untouched users.UpdateOne( alosdbclient.Document{"name": "Alice"}, alosdbclient.Document{"$set": alosdbclient.Document{ "age": 31, "active": true, }}, ) // Update nested fields with dot notation users.UpdateOne( alosdbclient.Document{"name": "Alice"}, alosdbclient.Document{"$set": alosdbclient.Document{ "address.city": "Melbourne", }}, )
// Add to a numeric field (creates field with 0 if missing) users.UpdateOne( alosdbclient.Document{"name": "Alice"}, alosdbclient.Document{"$add": alosdbclient.Document{"balance": 100.50}}, ) // Subtract from a numeric field users.UpdateOne( alosdbclient.Document{"name": "Alice"}, alosdbclient.Document{"$sub": alosdbclient.Document{"balance": 25.00}}, ) // $inc is an alias for $add users.UpdateOne( alosdbclient.Document{"name": "Alice"}, alosdbclient.Document{"$inc": alosdbclient.Document{"loginCount": 1}}, )
$add, $sub, and $inc work on any numeric type (int, int64, float64). If the field does not exist, it defaults to 0. The result preserves the original field's type when possible.
// Append a single item to an array users.UpdateOne( alosdbclient.Document{"name": "Alice"}, alosdbclient.Document{"$push": alosdbclient.Document{"tags": "premium"}}, ) // Append multiple items at once users.UpdateOne( alosdbclient.Document{"name": "Alice"}, alosdbclient.Document{"$pushAll": alosdbclient.Document{ "tags": []interface{}{"beta", "vip"}, }}, )
$push appends a single value. $pushAll appends a slice of values. Both create the array if the field does not exist. Using these on a non-array field returns an error.
// Remove a specific value from an array users.UpdateOne( alosdbclient.Document{"name": "Alice"}, alosdbclient.Document{"$pull": alosdbclient.Document{"tags": "beta"}}, ) // Remove a nested document from an array by exact match users.UpdateOne( alosdbclient.Document{"name": "Alice"}, alosdbclient.Document{"$pull": alosdbclient.Document{ "permissions": alosdbclient.Document{"resource": "billing"}, }}, )
$pull removes every element that equals the given value. For objects, equality is a deep match on all fields. Using $pull on a non-array field returns an error.
// Remove one or more fields entirely users.UpdateOne( alosdbclient.Document{"name": "Alice"}, alosdbclient.Document{"$unset": alosdbclient.Document{ "tempToken": "", "legacyId": "", }}, ) // Rename a field (creates new field, deletes old one) users.UpdateOne( alosdbclient.Document{"name": "Alice"}, alosdbclient.Document{"$rename": alosdbclient.Document{ "oldName": "newName", }}, )
$unset accepts a document where each key is a field to delete (values are ignored). $rename moves a value from the old key to the new key. Both support dot-notation for nested fields. The value in $rename is the new field name.
// Without $set, the entire document is replaced users.UpdateOne( alosdbclient.Document{"_id": id}, alosdbclient.Document{ "name": "Alice", "age": 31, "role": "admin", "active": true, }, )
$set merges fields into the existing document. Without
$set, the update document completely replaces the original (except
_id is preserved).
Process documents through a pipeline of stages. Each stage transforms the data passed to the next:
| Stage | Description |
|---|---|
$match |
Filter documents (same syntax as FindMany queries) |
$group |
Group by field with accumulators ($sum, $avg, $min, $max) |
$sort |
Sort results (1 = ascending, -1 = descending) |
$project |
Include/exclude fields (1 = include, 0 = exclude) |
$limit |
Limit number of results |
// Count users per department results, _ := users.Aggregate([]alosdbclient.Document{ {"$match": alosdbclient.Document{"active": true}}, {"$group": alosdbclient.Document{ "_id": "$department", "count": alosdbclient.Document{"$sum": 1}, }}, {"$sort": alosdbclient.Document{"count": -1}}, }) for _, r := range results { fmt.Printf("Dept %v: %v users\n", r["_id"], r["count"]) }
// Average age by role results, _ := users.Aggregate([]alosdbclient.Document{ {"$group": alosdbclient.Document{ "_id": "$role", "avg_age": alosdbclient.Document{"$avg": "$age"}, "min_age": alosdbclient.Document{"$min": "$age"}, "max_age": alosdbclient.Document{"$max": "$age"}, }}, })
// Top 5 highest-scoring users, only name and score results, _ := users.Aggregate([]alosdbclient.Document{ {"$sort": alosdbclient.Document{"score": -1}}, {"$limit": 5}, {"$project": alosdbclient.Document{ "name": 1, "score": 1, }}, })
For large result sets, use aggregation with $sort and $limit for
pagination, or range queries on an indexed field:
// Cursor-based pagination: get next page after a known _id nextPage, _ := users.FindMany(alosdbclient.Document{ "_id": alosdbclient.Document{"$gt": lastID}, }) // Or use aggregation for offset-based pagination page2, _ := users.Aggregate([]alosdbclient.Document{ {"$sort": alosdbclient.Document{"created_at": -1}}, {"$limit": 20}, // page size })
Performance: Cursor-based pagination using $gt on
_id is O(log n) — it uses the B-tree index directly. Range queries
benchmark at ~8,200 ops/sec.