API Reference
Collection Class Fluent API for working with entities in a specific namespace. Provides find, create, update, delete, and upsert operations.
The Collection class provides a fluent API for working with entities in a specific namespace. Collections are obtained via db.collection(namespace) or through proxy-based access like db.Posts.
interface Collection < T = Record < string , unknown >> {
readonly namespace : string
find ( filter ?: Filter , options ?: FindOptions ) : Promise < PaginatedResult < Entity < T >>>
findOne ( filter ?: Filter , options ?: FindOptions ) : Promise < Entity < T > | null >
get ( id : string , options ?: GetOptions ) : Promise < Entity < T > | null >
create ( data : CreateInput < T >, options ?: CreateOptions ) : Promise < Entity < T >>
update ( id : string , update : UpdateInput < T >, options ?: UpdateOptions ) : Promise < Entity < T > | null >
delete ( id : string , options ?: DeleteOptions ) : Promise < DeleteResult >
deleteMany ( filter : Filter , options ?: DeleteOptions ) : Promise < DeleteResult >
upsert ( filter : Filter , update : UpdateInput < T >, options ?: UpsertOptions ) : Promise < Entity < T > | null >
upsertMany ( items : UpsertManyItem < T >[], options ?: UpsertManyOptions ) : Promise < UpsertManyResult >
}
import { ParqueDB, MemoryBackend } from 'parquedb'
const db = new ParqueDB ({ storage: new MemoryBackend () })
// Get a typed collection
interface Post {
title : string
content : string
status : 'draft' | 'published'
}
const posts = db. collection < Post >( 'posts' )
// Access via PascalCase property
const posts = db.Posts
// Access via lowercase property
const users = db.users
The namespace identifier for this collection.
readonly namespace : string
const posts = db. collection ( 'posts' )
console. log (posts.namespace) // 'posts'
Find entities matching a filter with optional pagination and sorting.
find (filter ?: Filter, options ?: FindOptions): Promise < PaginatedResult < Entity < T >>>
Name Type Required Description filterFilterNo MongoDB-style filter query optionsFindOptionsNo Query options for pagination, sorting, etc.
Property Type Description sortSortSpecSort order, e.g., { createdAt: -1 } for descending limitnumberMaximum number of results to return skipnumberNumber of results to skip (offset-based pagination) cursorstringCursor for cursor-based pagination projectProjectionField projection (include/exclude fields) populatePopulateSpecPopulate related entities includeDeletedbooleanInclude soft-deleted entities (default: false) asOfDateTime-travel: query as of a specific timestamp explainbooleanReturn query plan instead of executing hintstring | objectHint for index selection maxTimeMsnumberMaximum execution time in milliseconds
interface PaginatedResult < T > {
items : T [] // Array of matching entities
total ?: number // Total count (if available)
nextCursor ?: string // Cursor for next page
hasMore : boolean // Whether more results exist
}
// Find all entities
const all = await posts. find ()
// Find with simple equality filter
const published = await posts. find ({ status: 'published' })
// Find with operators
const popular = await posts. find ({
status: 'published' ,
viewCount: { $gte: 1000 },
})
// Find with logical operators
const featured = await posts. find ({
$or: [
{ featured: true },
{ viewCount: { $gte: 10000 } },
],
})
// Find with pagination
const page1 = await posts. find ({}, { limit: 20 })
const page2 = await posts. find ({}, {
limit: 20 ,
cursor: page1.nextCursor
})
// Find with sorting
const recent = await posts. find ({}, {
sort: { createdAt: - 1 },
limit: 10 ,
})
// Find with projection
const titles = await posts. find ({}, {
project: { title: 1 , status: 1 },
})
// Find with time-travel
const pastState = await posts. find ({}, {
asOf: new Date ( '2024-01-01' ),
})
// Find including deleted
const withDeleted = await posts. find ({}, {
includeDeleted: true ,
})
Find a single entity matching a filter.
findOne (filter ?: Filter, options ?: FindOptions): Promise < Entity < T > | null >
Name Type Required Description filterFilterNo MongoDB-style filter query optionsFindOptionsNo Query options
Entity<T> | null - The first matching entity or null if not found.
// Find first matching entity
const post = await posts. findOne ({ slug: 'hello-world' })
// Find with sorting (get the most recent)
const latest = await posts. findOne ({}, {
sort: { createdAt: - 1 },
})
// Find by email (unique field)
const user = await users. findOne ({ email: 'alice@example.com' })
Get a single entity by its ID.
get (id: string, options ?: GetOptions): Promise < Entity < T > | null >
Name Type Required Description idstringYes Entity ID (full 'ns/id' or just 'id') optionsGetOptionsNo Get options
Property Type Description includeDeletedbooleanInclude if soft-deleted asOfDateTime-travel: get state at specific time hydratestring[]Hydrate related entities maxInboundnumberMaximum inbound references to inline projectProjectionField projection
Entity<T> | null - The entity or null if not found.
// Get by full ID
const post = await posts. get ( 'posts/abc123' )
// Get by short ID (namespace is inferred)
const post = await posts. get ( 'abc123' )
// Get with hydrated relationships
const post = await posts. get ( 'abc123' , {
hydrate: [ 'author' , 'categories' ],
})
// Get historical state
const oldPost = await posts. get ( 'abc123' , {
asOf: new Date ( '2024-01-01' ),
})
// Get including deleted
const deletedPost = await posts. get ( 'abc123' , {
includeDeleted: true ,
})
// Get with projection
const titleOnly = await posts. get ( 'abc123' , {
project: { title: 1 },
})
Create a new entity in the collection.
create (data: CreateInput < T > , options ?: CreateOptions): Promise < Entity < T >>
Name Type Required Description dataCreateInput<T>Yes Entity data to create optionsCreateOptionsNo Create options
Property Type Required Description $typestringYes Entity type name (e.g., 'Post', 'User') namestringYes Human-readable display name ...fieldsunknownNo Additional data fields
Property Type Description actorEntityIdWho is creating the entity (for audit trail) skipValidationbooleanSkip schema validation returnDocumentbooleanReturn created entity (default: true)
Entity<T> - The created entity with:
$id: Generated unique identifier (format: 'namespace/id')
createdAt / updatedAt: Timestamps
createdBy / updatedBy: Actor references
version: 1 (initial version)
// Create a basic entity
const post = await posts. create ({
$type: 'Post' ,
name: 'My First Post' ,
title: 'Hello World' ,
content: 'This is my first post!' ,
status: 'draft' ,
})
console. log (post.$id) // 'posts/abc123'
console. log (post.version) // 1
console. log (post.createdAt) // Date
// Create with actor for audit
const post = await posts. create ({
$type: 'Post' ,
name: 'Admin Post' ,
title: 'Announcement' ,
content: 'Important news...' ,
}, {
actor: 'users/admin' as EntityId ,
})
// Create with relationships
const post = await posts. create ({
$type: 'Post' ,
name: 'Tech Article' ,
title: 'Database Design' ,
author: { 'Alice' : 'users/alice' },
categories: {
'Technology' : 'categories/tech' ,
'Databases' : 'categories/db' ,
},
})
Update an existing entity.
update (id: string, update: UpdateInput < T > , options ?: UpdateOptions): Promise < Entity < T > | null >
Name Type Required Description idstringYes Entity ID to update updateUpdateInput<T>Yes Update operations optionsUpdateOptionsNo Update options
Update operations using MongoDB-style operators:
Operator Description Example $setSet field values { $set: { status: 'published' } }$unsetRemove fields { $unset: { tempField: '' } }$incIncrement numeric field { $inc: { viewCount: 1 } }$mulMultiply numeric field { $mul: { price: 1.1 } }$minSet to minimum value { $min: { lowScore: score } }$maxSet to maximum value { $max: { highScore: score } }$pushPush to array { $push: { tags: 'new' } }$pullRemove from array { $pull: { tags: 'old' } }$addToSetAdd unique to array { $addToSet: { tags: 'unique' } }$popRemove first/last from array { $pop: { queue: 1 } }$currentDateSet to current date { $currentDate: { updatedAt: true } }$linkAdd relationship { $link: { author: 'users/123' } }$unlinkRemove relationship { $unlink: { author: 'users/123' } }$setOnInsertSet only on insert (with upsert) { $setOnInsert: { createdBy: 'system' } }
Property Type Description actorEntityIdWho is updating (for audit trail) expectedVersionnumberExpected version for optimistic locking upsertbooleanCreate if entity doesn't exist returnDocument'before' | 'after'Return state before or after update skipValidationbooleanSkip schema validation arrayFiltersFilter[]Filters for positional array updates
Entity<T> | null - Updated entity, or null if not found (and upsert is false).
// Simple field update
const post = await posts. update ( 'abc123' , {
$set: { status: 'published' , publishedAt: new Date () },
})
// Increment counter
await posts. update ( 'abc123' , {
$inc: { viewCount: 1 },
})
// Multiple operators
await posts. update ( 'abc123' , {
$set: { status: 'featured' },
$inc: { featureCount: 1 },
$currentDate: { lastFeaturedAt: true },
})
// Array operations
await posts. update ( 'abc123' , {
$push: { tags: 'featured' },
$addToSet: { categories: 'popular' },
})
// Push with modifiers
await posts. update ( 'abc123' , {
$push: {
comments: {
$each: [newComment1, newComment2],
$position: 0 , // Insert at beginning
$slice: 100 , // Keep only 100 items
},
},
})
// Relationship operations
await posts. update ( 'abc123' , {
$link: {
author: 'users/alice' as EntityId ,
categories: [ 'categories/tech' , 'categories/db' ] as EntityId [],
},
})
// Unlink relationships
await posts. update ( 'abc123' , {
$unlink: { categories: 'categories/old' as EntityId },
})
// With optimistic concurrency
try {
await posts. update ( 'abc123' , {
$set: { title: 'New Title' },
}, {
expectedVersion: 5 ,
})
} catch (error) {
if (error instanceof VersionConflictError ) {
console. log ( 'Conflict detected, please retry' )
}
}
// Upsert (create if not exists)
await posts. update ( 'new-post' , {
$set: { title: 'New Post' },
$setOnInsert: {
$type: 'Post' ,
name: 'New Post' ,
status: 'draft' ,
},
}, {
upsert: true ,
})
// Return document before update
const original = await posts. update ( 'abc123' , {
$set: { status: 'archived' },
}, {
returnDocument: 'before' ,
})
Delete an entity (soft delete by default).
delete ( id : string , options ?: DeleteOptions ) : Promise < DeleteResult >
Name Type Required Description idstringYes Entity ID to delete optionsDeleteOptionsNo Delete options
Property Type Description actorEntityIdWho is deleting (for audit trail) hardbooleanPermanently delete (skip soft delete) expectedVersionnumberExpected version for optimistic locking
interface DeleteResult {
deletedCount : number // Number of entities deleted (0 or 1)
}
// Soft delete (default)
const result = await posts. delete ( 'abc123' )
console. log (result.deletedCount) // 1
// Hard delete (permanent)
await posts. delete ( 'abc123' , { hard: true })
// With optimistic concurrency
await posts. delete ( 'abc123' , {
expectedVersion: 5 ,
})
// With actor for audit trail
await posts. delete ( 'abc123' , {
actor: 'users/admin' as EntityId ,
})
Delete multiple entities matching a filter.
deleteMany (filter: Filter, options ?: DeleteOptions): Promise < DeleteResult >
Name Type Required Description filterFilterYes Filter to match entities to delete optionsDeleteOptionsNo Delete options
interface DeleteResult {
deletedCount : number // Total number of entities deleted
}
// Delete all drafts
const result = await posts. deleteMany ({ status: 'draft' })
console. log ( `Deleted ${ result . deletedCount } drafts` )
// Delete old posts
await posts. deleteMany ({
createdAt: { $lt: new Date ( '2023-01-01' ) },
})
// Hard delete spam
await posts. deleteMany (
{ spam: true },
{ hard: true }
)
Find and update an entity, or create it if not found.
upsert (
filter: Filter,
update: UpdateInput < T > ,
options ?: { returnDocument?: 'before' | 'after' }
): Promise < Entity < T > | null >
Name Type Required Description filterFilterYes Filter to find existing entity updateUpdateInput<T>Yes Update operations optionsobjectNo Options
Entity<T> | null - The updated or created entity.
Find entity matching filter
If found: apply update operations
If not found: create new entity with:
Non-operator fields from filter
Values from $set
Values from $setOnInsert
// Upsert user by email
const user = await users. upsert (
{ email: 'alice@example.com' },
{
$set: { lastLogin: new Date () },
$setOnInsert: {
$type: 'User' ,
name: 'Alice' ,
role: 'member' ,
},
}
)
// Upsert with increment
const stats = await stats. upsert (
{ date: today },
{
$inc: { pageViews: 1 },
$setOnInsert: {
$type: 'DailyStats' ,
name: `Stats ${ today }` ,
},
}
)
Upsert multiple entities in a single operation.
upsertMany (
items: UpsertManyItem < T > [],
options ?: UpsertManyOptions
): Promise < UpsertManyResult >
Name Type Required Description itemsUpsertManyItem<T>[]Yes Array of upsert items optionsUpsertManyOptionsNo Batch options
interface UpsertManyItem < T > {
filter : Filter // Filter to find existing
update : UpdateInput < T > // Update operations
options ?: {
expectedVersion ?: number // Optimistic concurrency
}
}
Property Type Description orderedbooleanStop on first error (default: true) actorEntityIdActor for all operations
interface UpsertManyResult {
ok : boolean // All operations succeeded
insertedCount : number // New entities created
modifiedCount : number // Existing entities updated
matchedCount : number // Entities matched by filters
upsertedCount : number // Total upserted (inserted)
upsertedIds : EntityId [] // IDs of new entities
errors : UpsertManyError [] // Errors that occurred
}
interface UpsertManyError {
index : number // Index of failed item
filter : Filter // Filter that was used
error : Error // The error
}
// Bulk upsert users
const result = await users. upsertMany ([
{
filter: { email: 'alice@example.com' },
update: {
$set: { name: 'Alice Smith' },
$setOnInsert: { $type: 'User' , role: 'member' },
},
},
{
filter: { email: 'bob@example.com' },
update: {
$set: { name: 'Bob Jones' },
$setOnInsert: { $type: 'User' , role: 'member' },
},
},
])
console. log ( `Inserted: ${ result . insertedCount }` )
console. log ( `Modified: ${ result . modifiedCount }` )
// Continue on errors
const result = await users. upsertMany (items, {
ordered: false , // Don't stop on first error
})
if ( ! result.ok) {
for ( const error of result.errors) {
console. error ( `Item ${ error . index } failed:` , error.error.message)
}
}
Collections support MongoDB-style filter operators:
Operator Description Example $eqEqual { status: { $eq: 'published' } }$neNot equal { status: { $ne: 'draft' } }$gtGreater than { score: { $gt: 100 } }$gteGreater than or equal { score: { $gte: 100 } }$ltLess than { score: { $lt: 50 } }$lteLess than or equal { score: { $lte: 50 } }$inIn array { status: { $in: ['draft', 'review'] } }$ninNot in array { status: { $nin: ['deleted'] } }
Operator Description Example $andAll conditions match { $and: [{ a: 1 }, { b: 2 }] }$orAny condition matches { $or: [{ a: 1 }, { b: 2 }] }$notNegation { $not: { status: 'draft' } }$norNone match { $nor: [{ a: 1 }, { b: 2 }] }
Operator Description Example $regexRegular expression { title: { $regex: '^Hello' } }$startsWithStarts with prefix { title: { $startsWith: 'Hello' } }$endsWithEnds with suffix { title: { $endsWith: '!' } }$containsContains substring { title: { $contains: 'world' } }
Operator Description Example $allArray contains all { tags: { $all: ['a', 'b'] } }$elemMatchElement matches { items: { $elemMatch: { qty: { $gt: 5 } } } }$sizeArray size { tags: { $size: 3 } }
Operator Description Example $existsField exists { email: { $exists: true } }$typeField type check { data: { $type: 'object' } }
Operator Description Example $textFull-text search { $text: { $search: 'hello world' } }$vectorVector similarity { $vector: { $near: vec, $k: 10 } }$geoGeospatial query { $geo: { $near: { lng, lat } } }
// Entity type properly uses TData for typed data fields
type Entity < TData = Record < string , unknown >> = EntityRef & AuditFields & TData & {
[ key : string ] : unknown
}
interface EntityRef {
$id : EntityId // Full entity ID (namespace/id)
$type : string // Entity type name
name : string // Display name
}
interface AuditFields {
createdAt : Date // Creation timestamp
createdBy : EntityId // Creator ID
updatedAt : Date // Last update timestamp
updatedBy : EntityId // Last updater ID
deletedAt ?: Date // Soft delete timestamp
deletedBy ?: EntityId // Who deleted
version : number // Version number
}
interface SortSpec {
[ field : string ] : 1 | - 1 | 'asc' | 'desc'
}
// Examples:
{ createdAt : - 1 } // Descending
{ createdAt : 'desc' } // Same as above
{ name : 1 , createdAt : - 1 } // Multi-field sort
interface Projection {
[ field : string ] : 0 | 1 | boolean
}
// Examples:
{ title : 1 , content : 1 } // Include only these
{ password : 0 } // Exclude this field
type PopulateSpec =
| string [] // ['author', 'categories']
| { [ predicate : string ] : boolean | PopulateOptions }
interface PopulateOptions {
limit ?: number
sort ?: SortSpec
cursor ?: string
filter ?: Filter
populate ?: PopulateSpec // Nested populate
}
Thrown when optimistic concurrency check fails.
import { VersionConflictError } from 'parquedb'
try {
await posts. update ( 'abc123' ,
{ $set: { title: 'New' } },
{ expectedVersion: 5 }
)
} catch (error) {
if (error instanceof VersionConflictError ) {
console. log ( `Expected ${ error . expectedVersion }, got ${ error . actualVersion }` )
// Handle conflict (retry, merge, etc.)
}
}
Thrown when entity data fails schema validation.
try {
await posts. create ({
$type: 'Post' ,
name: 'Test' ,
// Missing required 'title' field
})
} catch (error) {
console. log (error.message) // 'Missing required field: title'
}
interface Post {
title : string
content : string
status : 'draft' | 'published'
viewCount : number
}
const posts = db. collection < Post >( 'posts' )
// Now you get type safety
const post = await posts. create ({
$type: 'Post' ,
name: 'My Post' ,
title: 'Hello' ,
content: 'World' ,
status: 'draft' , // TypeScript validates this
viewCount: 0 ,
})
async function* getAllPosts () {
let cursor : string | undefined
while ( true ) {
const result = await posts. find ({}, {
limit: 100 ,
cursor,
sort: { createdAt: - 1 },
})
for ( const post of result.items) {
yield post
}
if ( ! result.hasMore) break
cursor = result.nextCursor
}
}
for await ( const post of getAllPosts ()) {
console. log (post.title)
}
async function updateWithRetry ( id : string , update : UpdateInput , maxRetries = 3 ) {
for ( let attempt = 0 ; attempt < maxRetries; attempt ++ ) {
const current = await posts. get (id)
if ( ! current) throw new Error ( 'Not found' )
try {
return await posts. update (id, update, {
expectedVersion: current.version,
})
} catch (error) {
if (error instanceof VersionConflictError && attempt < maxRetries - 1 ) {
continue // Retry
}
throw error
}
}
}
// Prefer upsertMany for bulk operations
const result = await posts. upsertMany (
items. map ( item => ({
filter: { externalId: item.id },
update: {
$set: item.data,
$setOnInsert: { $type: 'Post' , name: item.title },
},
})),
{ ordered: false } // Continue on errors
)