Collections
db.collection(name) returns a Collection<T> wrapper that calls server endpoints.
If you pass a schema + schema version (db.collection(name, schema, schemaVersion)), the driver can also:
- parse documents through
schema.parse(...), and - auto-manage a
__vfield and client-side read migrations.
See Schemas & migrations for the full workflow.
Related page: Databases (collection creation/rename/drop, indexes, transactions, credentials).
CRUD
insertOne(doc): Promise<T>insertMany(docs): Promise<T[]>insertManyStream(docs, options?): Promise<number>find(filter = {}): Promise<T[]>findOne(filter = {}): Promise<T | null>updateOne(filter, update, options?): Promise<T | null>updateMany(filter, update): Promise<{ updated; docs }>deleteOne(filter): Promise<T | null>deleteMany(filter): Promise<{ deleted: number }count(filter = {}): Promise<number>countDocuments(filter = {}): Promise<number>aggregate(pipeline?): Promise<{ results }>stats(): Promise<...>compact(): Promise<...>
Examples (tiny per method)
insertOne(doc)
- TypeScript
- JavaScript
import { LioranClient } from "@liorandb/driver";
const client = new LioranClient("http://localhost:4000");
await client.login("admin", "admin");
const db = await client.db("default");
const users = db.collection<{ userId: string; role: string }>("users");
await users.insertOne({ userId: "u1", role: "user" });
console.log(await users.count({ role: "user" }));
import { LioranClient } from "@liorandb/driver";
const client = new LioranClient("http://localhost:4000");
await client.login("admin", "admin");
const db = await client.db("default");
const users = db.collection("users");
await users.insertOne({ userId: "u1", role: "user" });
console.log(await users.count({ role: "user" }));
insertMany(docs)
- TypeScript
- JavaScript
await users.insertMany([
{ userId: "u2", role: "user" },
{ userId: "u3", role: "admin" },
]);
await users.insertMany([
{ userId: "u2", role: "user" },
{ userId: "u3", role: "admin" },
]);
insertManyStream(docs, options?) (NDJSON streaming)
For large inserts, you can stream documents using NDJSON. This avoids building a giant array in memory.
insertManyStream(...) accepts an Iterable or AsyncIterable and returns the number of inserted documents (as reported by the server response).
async function* docs() {
for (let i = 0; i < 10_000; i++) {
yield { userId: `u${i}`, role: "user", createdAt: Date.now() };
}
}
const inserted = await users.insertManyStream(docs(), { chunkSize: 1000 });
console.log({ inserted });
find(filter?, options?)
find() and findOne() accept an optional options object:
limit?: numberoffset?: numberprojection?: string[]sort?: Record<string, 1 | -1>sortBy?: string(convenience for a single-field sort)sortDir?: "asc" | "desc" | 1 | -1 | "1" | "-1"
- TypeScript
- JavaScript
console.log(await users.find({ role: "user" }, { limit: 10, offset: 0 }));
console.log(await users.find({ role: "user" }, { sortBy: "userId", sortDir: "desc" }));
console.log(await users.find({ role: "user" }, { limit: 10, offset: 0 }));
console.log(await users.find({ role: "user" }, { sortBy: "userId", sortDir: "desc" }));
Embedding options inside the query (__options)
If it is more convenient for your codebase, you can embed options inside the filter object under a reserved __options key:
await users.find({
role: "user",
__options: { limit: 10, sortBy: "userId", sortDir: -1 },
});
If you pass both embedded __options and an explicit options argument, the explicit argument wins.
findOne(filter?, options?)
- TypeScript
- JavaScript
console.log(await users.findOne({ userId: "u1" }));
console.log(await users.findOne({ userId: "u1" }));
updateOne(filter, update, options?)
Supports update operators like $set, $inc, $unset. Use { upsert: true } to insert when missing.
- TypeScript
- JavaScript
console.log(
await users.updateOne(
{ userId: "u1" },
{ $set: { role: "admin" } },
{ upsert: true }
)
);
console.log(
await users.updateOne(
{ userId: "u1" },
{ $set: { role: "admin" } },
{ upsert: true }
)
);
updateMany(filter, update)
- TypeScript
- JavaScript
const out = await users.updateMany({ role: "user" }, { $set: { active: true } });
console.log(out.updated);
const out = await users.updateMany({ role: "user" }, { $set: { active: true } });
console.log(out.updated);
deleteOne(filter) / deleteMany(filter)
- TypeScript
- JavaScript
console.log(await users.deleteOne({ userId: "u3" }));
console.log(await users.deleteMany({ active: false }));
console.log(await users.deleteOne({ userId: "u3" }));
console.log(await users.deleteMany({ active: false }));
count(filter?) / countDocuments(filter?)
- TypeScript
- JavaScript
console.log(await users.count({ role: "admin" }));
console.log(await users.countDocuments({ role: "admin" }));
console.log(await users.count({ role: "admin" }));
console.log(await users.countDocuments({ role: "admin" }));
Aggregation
aggregate(pipeline?)
- TypeScript
- JavaScript
const out = await users.aggregate([{ $group: { _id: "role", count: { $sum: 1 } } }]);
console.log(out);
const out = await users.aggregate([{ $group: { _id: "role", count: { $sum: 1 } } }]);
console.log(out);
Indexes
listIndexes() / createIndex(field, options?) / dropIndex(field)
- TypeScript
- JavaScript
console.log(await users.listIndexes());
console.log(await users.createIndex("userId", { unique: true }));
console.log(await users.dropIndex("userId"));
console.log(await users.listIndexes());
console.log(await users.createIndex("userId", { unique: true }));
console.log(await users.dropIndex("userId"));
rebuildIndex(field) / rebuildIndexes()
- TypeScript
- JavaScript
console.log(await users.rebuildIndex("role"));
console.log(await users.rebuildIndexes());
console.log(await users.rebuildIndex("role"));
console.log(await users.rebuildIndexes());
explain(filter?, options?)
- TypeScript
- JavaScript
console.log(await users.explain({ role: "admin" }, { limit: 5 }));
console.log(await users.explain({ role: "admin" }, { limit: 5 }));
Text indexes: createTextIndex(field, options?) / dropTextIndex(field)
Text indexes are used by the $text query operator (see below).
await users.createTextIndex("title", { normalize: true, stopwords: ["a", "the"] });
await users.dropTextIndex("title");
rebuildTextIndex(field)
await users.rebuildTextIndex("title");
Text search ($text)
Use $text at the top level of your filter. This requires at least one text index.
await users.find({ $text: { $search: "hello world" } });
await users.find({ $text: { $search: "hello world", $fields: ["title", "body"] } });
Dates and timestamps
The driver talks to the server over JSON. If you pass a JavaScript Date into a document, it will serialize as an ISO string.
Recommended pattern:
await users.insertOne({ createdAt: Date.now() }); // epoch ms number
Maintenance
stats() / compact()
- TypeScript
- JavaScript
console.log(await users.stats());
console.log(await users.compact());
console.log(await users.stats());
console.log(await users.compact());
Collection options
The server can store per-collection options. The driver exposes:
getOptions()setDateOption(date)(convenience for the commondateoption)
console.log(await users.getOptions());
await users.setDateOption({ mode: "epoch_ms" });
Server-side collection doc migrations
Separate from the driver’s client-side addMigration(...), the server can maintain its own collection doc-migration configuration:
getDocMigrations()setDocMigrations(config | null)testDocMigration(doc)