Introducing AI Conversations: Natural Language Interaction for Your Apps! Learn More
DocumentDB Releases
6.1.0 - June 2, 2026
Section titled “6.1.0 - June 2, 2026” Feature
PageResult(page, pageSize, zeroBased?) extension on IDocumentQuery<T> — runs the query and returns PagedResults<T> { Records, TotalCount, Page, PageSize } in one call. TotalCount reflects the current Where filters (and global query filters) — pagination state is ignored when counting. 1-based by default to match common UI/REST conventions; pass zeroBased: true for 0-based indexing. Overrides any prior .Paginate(...) call on the query. See Pagination Feature
String-based
OrderBy / OrderByDescending extensions on IDocumentQuery<T> — sort by a property identified at runtime by name (query.OrderBy("Name", ctx.User)). Matches case-insensitively against either the CLR property name or the JSON property name (after naming policy). Supports dotted paths for nested properties ("ShippingAddress.City"). Fully AOT-safe: resolution walks JsonTypeInfo.Properties (source-generated) and synthesizes an Expression.Property(parameter, PropertyInfo) tree — no Type.GetProperty(string) reflection on T, no Expression.Compile(). Intended for dynamic UIs where the sort column is user-selected at runtime. See Ordering6.0 - July 1, 2026
Section titled “6.0 - July 1, 2026” Feature
Composite / multi-column JSON indexes —
CreateIndexAsync<T>(JsonTypeInfo<T>, params IEnumerable<Expression<Func<T, object>>>) (and matching DropIndexAsync) build a single B-tree over multiple JSON paths. SQLite, SQLCipher, PostgreSQL, MySQL, and DuckDB emit one composite index with one expression per path; SQL Server adds a PERSISTED computed column per path (cc_{indexName}_0, cc_{indexName}_1, …) and indexes them all. Existing single-path overloads keep the legacy index/column names so nothing on disk has to change. Drop discovers the index’s backing computed columns via sys.index_columns and removes them after the index, so single- and multi-column drops use the same code path. See Indexes › Composite Feature
Vector / ANN search — register an embedding property with
MapVectorProperty<T>(d => d.Embedding, dimensions: 1536, metric: VectorDistance.Cosine, indexKind: VectorIndexKind.Hnsw) and query with store.Query<T>().Where(...).NearestVectors(queryEmbedding, k: 10). Returns VectorResult<T> ({ Document, Score }) ordered nearest first. Provider-native indexes: pgvector (PostgreSQL HNSW/IVF + all four metrics including Hamming), native VECTOR(n) + VECTOR_DISTANCE (SQL Server 2025, DiskANN), embedding policy + VectorDistance() (CosmosDB DiskANN/QuantizedFlat/Flat), $vectorSearch aggregation (MongoDB Atlas HNSW), vss extension (DuckDB HNSW), sqlite-vec virtual table (SQLite flat scan with post-filter candidate multiplier). Pre-filter via Where(...) on every provider that supports it; SQLite post-filters with a configurable multiplier. Cosine score is always surfaced as distance in [0, 2] regardless of provider convention. LiteDB, IndexedDB, and MySQL throw NotSupportedException. See Vector Feature
AutoEmbedOnInsert<T> (Shiny.DocumentDb.Extensions.AI) — plug Microsoft.Extensions.AI.IEmbeddingGenerator<string, Embedding<float>> into the new DocumentStoreOptions.OnBeforeInsert<T> pipeline so a text property is automatically embedded into a ReadOnlyMemory<float> field on Insert, BatchInsert, and Upsert. Skips when the source is null/empty or when the target already holds a non-default vector — explicit writes win over the generator. See Vector › Auto-embed Feature
VectorIndexOptions — strongly-typed knobs for HNSW (M, EfConstruction, EfSearch) and IVF (Lists) plus a ProviderHints dictionary for the long tail (sqlite.postFilterMultiplier, atlas.indexName, atlas.numCandidates) Feature
OnBeforeInsert<T> hook on DocumentStoreOptions — register an async handler that runs on every document before serialization on Insert/BatchInsert/Upsert. Handlers run in registration order. Used by AutoEmbedOnInsert<T> but available for any “compute derived fields” scenario Feature
SupportsVector property on IDocumentStore and IDatabaseProvider — check vector-search availability at runtime. IDocumentStore.NearestVectors<T>(query, k, filter?) is on the interface with a default-throwing implementation, so existing providers compile without changes Feature
Concurrent operations on server SQL providers —
DocumentStore now opens a connection per operation on PostgreSQL, MySQL, and SQL Server, relying on the ADO.NET driver’s built-in connection pool. A single store instance can serve concurrent callers without the operation-serializing semaphore that previous releases used. SQLite and DuckDB (embedded engines) keep the long-lived shared connection + semaphore model — opt in by overriding IDatabaseProvider.RequiresSingleConnection => true. Table init is now backed by a ConcurrentDictionary<string, Lazy<Task>> so first-touch DDL runs exactly once per table even under concurrent first calls. RunInTransaction pins one connection for the user callback so nested ops share the transaction Fix
PostgreSQL & DuckDB multi-tenancy was silently broken — providers that wrap
@data in a CAST(...) expression (Postgres’ CAST(@data AS JSONB), DuckDB’s CAST(@data AS JSON)) skipped the value-list rewrite, so INSERT ended up with 6 columns and 5 values. The substitution now anchors on (@id, @typeName, so it survives provider variations Fix
PostgreSQL optimistic concurrency was broken — the version check used
Data #>> '{Version}' = @expectedVersion, which Postgres rejects with 42883: operator does not exist: text = integer. Switched to JsonExtractTyped(..., typeof(int)) so providers emit the proper ::BIGINT (or equivalent) cast on the extracted value Feature
New
Shiny.DocumentDb.MongoDb package — MongoDB provider for Shiny.DocumentDb. Implements the full IDocumentStore API over MongoDB.Driver, storing each document as a typed BSON envelope (_id = "{TypeName}:{Id}", id, typeName, data, createdAt, updatedAt) inside a configurable collection. Includes MapTypeToCollection<T> for collection-per-type isolation, MapVersionProperty<T> for optimistic concurrency, and a sharable MongoClient for pooled clients. See MongoDB Feature
New
Shiny.DocumentDb.DuckDb package — embedded analytical store backed by DuckDB. Plugs into the standard IDatabaseProvider pipeline like SQLite/Postgres/MySQL/SQL Server, with native JSON column storage and server-side RFC 7396 Upsert via DuckDB’s json_merge_patch. The json extension is auto-loaded on every connection. See DuckDB Feature
In-process change monitoring (
IObservableDocumentStore) — consume an IAsyncEnumerable<DocumentChange<T>> of insert/update/remove/clear events with await foreach (var c in store.NotifyOnChange<User>(ct)). Channel-based fan-out — each subscriber gets its own bounded reader and unsubscribes automatically when the iterator exits or the token cancels. Changes inside RunInTransaction are buffered and emitted on commit; rollbacks discard them. Supported on DocumentStore (SQLite, SQLCipher, MySQL, SQL Server, PostgreSQL) and LiteDbDocumentStore. See Change Monitoring Feature
Per-query change monitoring — every fluent query exposes
.NotifyOnChange(ct) which filters the change stream by the query’s Where predicates: store.Query<Order>().Where(o => o.Status == "Pending").NotifyOnChange(ct). OrderBy, Paginate, and GroupBy are ignored (they affect result shape, not membership). Throws after Select(...). Property-level events (SetProperty/RemoveProperty/Remove/Clear, where Document == null) are passed through unconditionally so consumers can re-query Feature
WhenDocumentChanged<T>(id) extension — filters the in-process change stream to events for a single document Id (plus Cleared, which affects every document of the type) Feature
Native change feeds (
IChangeFeedDocumentStore) — SubscribeChanges<T> observes the underlying database itself, including writes from other processes / connections / store instances. PostgreSQL uses LISTEN/NOTIFY with row-level triggers (true push), SQL Server uses Change Tracking with optional SqlDependency query notifications (configurable via SqlServerChangeFeedOptions), and Cosmos DB uses the native Change Feed API with an auto-provisioned lease container. Provisioning is automatic and idempotent. Throws NotSupportedException on SQLite, LiteDB, IndexedDB, MySQL, and DuckDB Feature
DocumentChange<T> envelope — ChangeType (Inserted / Updated / Removed / Cleared), Id, and Document (populated for Inserted and full-document Updated; null for Removed / Cleared / property-level updates) Feature
MapIdProperty<T>(...) — standalone Id-property override that no longer requires MapTypeToTable. Use it when the document Id is not literally named Id (e.g. BlogPost.Slug) but you still want the type stored in the default shared table. Expression and AOT-safe string overloads Feature
Global query filters (
AddQueryFilter<T>) — register a predicate that’s automatically AND-applied to every query of T, mirroring Entity Framework Core’s HasQueryFilter. Supports unnamed and named filters (AddQueryFilter<T>("name", ...)) with per-query opt-out via IgnoreQueryFilters() or IgnoreQueryFilters("name"). Filters apply to Query<T>() and every terminal, single-document operations (Get/Update/Remove/SetProperty/RemoveProperty/Clear), bulk operations (ExecuteUpdate/ExecuteDelete), and per-query change monitoring. Insert/BatchInsert/Upsert and raw SQL are intentionally unfiltered (matches EF Core). Captured variables are re-read on every translation, so per-request values (multi-tenancy, soft-delete, row-level scopes) work without rebuilding the store. Available on DocumentStoreOptions, LiteDbDocumentStoreOptions, CosmosDbDocumentStoreOptions, MongoDbDocumentStoreOptions, and IndexedDbDocumentStoreOptions. See Global Query Filters Feature
MongoDB
Upsert performs RFC 7396 deep merge in C# with recursive null stripping, matching CosmosDB / LiteDB / IndexedDB semantics Feature
MongoDB
RunInTransaction uses a compensating model (track inserts, delete on failure) for single-node deployments. Matches the CosmosDB provider’s behaviour. Use a replica set + custom session for true ACID multi-document transactions Feature
DuckDB
SetProperty and RemoveProperty are implemented via json_merge_patch — DuckDB has no json_set/json_remove, so the JSON path is folded into a synthetic merge-patch document server-side using list_reduce. RFC 7396 null = delete semantics are preserved on RemoveProperty Feature
DuckDB
Query<T>(string) / QueryStream<T>(string) raw SQL parity with the other SQL providers (use json_extract_string(Data, '$.path')) Feature
Provider matrix in Provider Reference updated with DuckDB and MongoDB columns covering storage type, raw SQL support, predicate translation, deep merge, spatial, backup, and transactions
5.2.2 - May 30, 2026
Section titled “5.2.2 - May 30, 2026” Fix
SQL Server
CreateIndexAsync emitted broken DDL — the jsonPath argument was ignored; every JSON-path index registration silently produced a useless index on the TypeName column. Indexes are now backed by a persisted computed column (cc_{indexName}) over JSON_VALUE(Data, '$.path'), with a filtered CREATE INDEX on that column. DropIndex now drops both the index and its backing computed column using the required DROP INDEX … ON [table] syntax Fix
Upsert deep-merge was shallow on PostgreSQL and SQL Server — Postgres used the
jsonb || jsonb concat operator (top-level only) and SQL Server used a flat OPENJSON … FULL OUTER JOIN, both of which clobbered nested objects. Neither database has a native RFC 7396 JSON_MERGE_PATCH. Both providers now perform a row-locked read-merge-write fallback in C# (using SELECT … FOR UPDATE on PG and WITH (UPDLOCK, HOLDLOCK) on SQL Server), keeping the documented RFC 7396 deep-merge semantics Fix
Null-stripping was shallow across all providers — when an Upsert patch contained a nested object whose other properties were null (e.g.
new Doc { Address = new Address { City = "X" } }), the unfilled street/state nulls reached the merge step and were interpreted as RFC 7396 deletions, silently wiping the stored values. Null-stripping is now recursive, so partial nested patches preserve unspecified fields on SQLite, MySQL, LiteDB, IndexedDB, Cosmos DB, PostgreSQL, and SQL Server Fix
MySQL —
DropIndexAsync emitted DROP INDEX {name};, which is invalid in MySQL. Now emits proper drop index on table5.2.1 - May 29, 2026
Section titled “5.2.1 - May 29, 2026” Feature
Unit of Work — new
CreateUnitOfWork() extension method on IDocumentStore returns a UnitOfWork that buffers Add/Update/Remove operations and applies them atomically inside a single transaction on Commit(). The queue is auto-cleared on successful commit; on failure the transaction is rolled back and the queue is preserved for inspection or retry. Works across every provider via RunInTransaction. See Unit of Work5.2 - May 27, 2026
Section titled “5.2 - May 27, 2026” Feature
Shiny.DocumentDb.IndexedDb is now 100% AOT/reflection-free. The JS interop layer was rewritten to use
[JSImport] from System.Runtime.InteropServices.JavaScript instead of IJSRuntime.InvokeAsync. The library no longer requires JsonSerializerIsReflectionEnabledByDefault=true to function — apps targeting AOT or trim-safe deployments can use the IndexedDB provider without re-enabling reflection Feature
Internal source-generated
JsonSerializerContext (camelCase) for DocumentRecord wire-format serialization — the library no longer depends on the consuming app’s JsonSerializerOptions for envelope types. Existing IndexedDB databases remain readable; the wire format is unchanged Feature
Module loading switched from
IJSRuntime.InvokeAsync<IJSObjectReference>("import", ...) to JSHost.ImportAsync(...). No app-side changes required Fix
IndexedDbDocumentStore no longer throws JsonSerializerIsReflectionDisabled when the host app has reflection disabled. In 5.1 and earlier, the library’s reliance on Blazor’s IJSRuntime Object[] arg envelope forced apps targeting AOT to either drop the IndexedDB provider or globally re-enable reflection5.1 - May 26, 2026
Section titled “5.1 - May 26, 2026” Fix
Query operations (
Count, Any, ToList, ToAsyncEnumerable, ExecuteDelete, ExecuteUpdate, Max, Min, Sum, Average, and projected Select queries) now initialize the type-specific table before executing. Previously, the query path always initialized the default TableName, so calling a query method against a type registered with MapTypeToTable<T>() before any insert had created its table raised no such table: <Name> Fix
SQLite — table identifiers are now properly quoted in all generated DDL/DML. Mapping a type whose name collides with a SQL reserved word (e.g.
Order, Group, User) no longer produces syntax error at table creation or insert time5.0 - May 6, 2026
Section titled “5.0 - May 6, 2026”Backup removed from IDocumentStore interface — now available only on concrete types: SqliteDocumentStore.Backup(), SqlCipherDocumentStore.Backup(), and LiteDbDocumentStore.Backup()Provider-specific DI extension methods removed (
AddSqliteDocumentStore, AddSqlCipherDocumentStore, AddSqlServerDocumentStore, AddMySqlDocumentStore, AddPostgreSqlDocumentStore, AddLiteDbDocumentStore, AddCosmosDbDocumentStore, AddIndexedDbDocumentStore). Use AddDocumentStore from Shiny.DocumentDb.Extensions.DependencyInjection instead Feature
Named/keyed document store support —
AddDocumentStore("name", opts => ...) registers stores as .NET keyed singletons. Inject with [FromKeyedServices("name")] or resolve dynamically via IDocumentStoreProvider.GetStore("name") Feature
Multi-tenancy support — two isolation strategies via
Shiny.DocumentDb.Extensions.DependencyInjection: shared-table (single database with automatic TenantId column filtering) and tenant-per-database (separate database per tenant via lazy factory) Feature
ITenantResolver interface — implement to provide the current tenant ID. Used by both multi-tenancy strategies to auto-resolve tenant context per request Feature
AddDocumentStore(configure, multiTenant: true) — shared-table multi-tenancy registration. Adds a dedicated TenantId column and index to the schema; all queries are automatically filtered by the current tenant Feature
AddMultiTenantDocumentStore(Func<string, DocumentStoreOptions>) — tenant-per-database registration. Each tenant gets a lazily-created separate database. IDocumentStore is registered as scoped and resolves to the correct tenant automatically Feature
TenantIdAccessor on DocumentStoreOptions — core pipeline hook for shared-table multi-tenancy. When set, all queries include a TenantId filter and all inserts include the tenant value. A dedicated column and index are created automatically Feature
New
Shiny.DocumentDb.IndexedDb package — IndexedDB provider for Blazor WebAssembly with IndexedDbDocumentStore. Zero native dependencies, persists to the browser’s IndexedDB via JS interop Feature
SQLite WASM compatibility —
SqliteDatabaseProvider now skips WAL pragma on OperatingSystem.IsBrowser(), spatial R*Tree is disabled in WASM, and Backup() is marked [UnsupportedOSPlatform("browser")] Feature
New
Shiny.DocumentDb.LiteDb package — LiteDB provider with LiteDbDocumentStore Feature
New
Shiny.DocumentDb.CosmosDb package — Azure Cosmos DB provider with CosmosDbDocumentStore Feature
Spatial/geo query support —
WithinRadius, WithinBoundingBox, and NearestNeighbors methods on IDocumentStore with default NotSupportedException for unsupported providers Feature
GeoPoint readonly record struct — represents a WGS84 coordinate, serializes as GeoJSON {"type":"Point","coordinates":[lng,lat]} Feature
GeoBoundingBox readonly record struct for area-based spatial queries Feature
SpatialResult<T> wrapper — returns documents with computed DistanceMeters from the query center point Feature
MapSpatialProperty<T> on DocumentStoreOptions — register which GeoPoint property to use for spatial indexing per document type Feature
SQLite spatial support via
R*Tree virtual tables — automatic sidecar table creation and CRUD sync for spatial-indexed documents Feature
CosmosDB spatial support via native
ST_DISTANCE and ST_WITHIN GeoJSON queries with automatic spatial index policy Feature
SupportsSpatial property on IDocumentStore — check if the current provider supports spatial queries at runtime Feature
SqliteDocumentStore.ClearAllAsync() — deletes all documents across all tables in the SQLite database, including spatial sidecar tables Feature
Optimistic concurrency via document-level version properties —
MapVersionProperty<T>(x => x.RowVersion) on all provider options classes. Version is set to 1 on insert, checked and incremented on update/upsert. Throws ConcurrencyException on mismatch. Stored inside the JSON blob — zero schema changes required Feature
AOT-safe
MapVersionProperty<T> overload — MapVersionProperty<T>(string propertyName, Func<T, int> getter, Action<T, int> setter) for trimming-safe deployments Feature
ConcurrencyException — new exception type with TypeName, DocumentId, ExpectedVersion, and ActualVersion properties for diagnosing version conflicts4.0 - April 30, 2026
Section titled “4.0 - April 30, 2026” Feature
New
Shiny.DocumentDb.Extensions.AI package — exposes IDocumentStore operations as Microsoft.Extensions.AI tool functions for LLM agents Feature
AddDocumentStoreAITools DI extension — opt-in registration of document types with per-type capability flags (ReadOnly, All, or individual Get/Query/Count/Aggregate/Insert/Update/Delete) Feature
Seven AI tool functions generated per type (when using
All): get_by_id, query, count, aggregate, insert, update, delete Feature
Structured JSON filter expressions with
and/or/not combinators and leaf comparisons (eq, ne, gt, gte, lt, lte, contains, startsWith, in) — translated to LINQ expressions at runtime Feature
Per-type builder API:
Description(), Property() description overrides, AllowProperties() / IgnoreProperties() for field visibility control, MaxPageSize() to cap query results Feature
AOT-safe — all tool schemas and serialization use
JsonTypeInfo<T> from source-generated JSON contexts Feature
Aggregate tool supports
count, sum, min, max, avg functions with optional structured filters Feature
DocumentStoreAITools wrapper class — resolve from DI and pass .Tools to IChatClient / ChatOptions.Tools Feature
GitHub Copilot sample app demonstrating interactive document management via LLM chat
3.2 - March 26, 2026
Section titled “3.2 - March 26, 2026” Feature
New
Shiny.DocumentDb.Sqlite.SqlCipher package — encrypted SQLite via SQLCipher with a separate native bundle, no changes to the existing Shiny.DocumentDb.Sqlite package Feature
SqlCipherDatabaseProvider(filePath, password) — explicit file path and password parameters so users know exactly what is required Feature
SqlCipherDocumentStore convenience wrapper and AddSqlCipherDocumentStore DI extension for quick setup Feature
RekeyAsync extension method on IDocumentStore — change the encryption key of an existing SQLCipher database via PRAGMA rekey with SQL injection protection Feature
Backup support for SQLCipher — automatically propagates the encryption password to the backup database
Feature
DocumentStore.DatabaseProvider public property — exposes the underlying IDatabaseProvider for extension methods3.1 - March 24, 2026
Section titled “3.1 - March 24, 2026”Removed
SystemTextJsonPatch dependency — replaced with built-in AOT-compatible JsonPatchDocument<T> and JsonPatchOperation types that use JSON DOM manipulation instead of reflectionJsonPatchDocument<T>.ApplyTo() now returns a new T instead of mutating the target in place — var patched = patch.ApplyTo(original) Feature
New
JsonPatchOperation immutable type with static factory methods: Add, Replace, Remove, Copy, Move, Test Feature
New
JsonPatchDocument<T> with AOT-safe overload accepting JsonTypeInfo<T> — patch.ApplyTo(target, MyJsonContext.Default.MyType) Feature
BatchInsert<T> now uses multi-row INSERT statements chunked into batches of 500 rows, significantly reducing database round-trips — especially impactful for PostgreSQL3.0 - March 23, 2026
Section titled “3.0 - March 23, 2026”Package renamed from
Shiny.SqliteDocumentDb to Shiny.DocumentDb with separate provider packages: Shiny.DocumentDb.Sqlite, Shiny.DocumentDb.SqlServer, Shiny.DocumentDb.MySql, Shiny.DocumentDb.PostgreSqlConnectionString removed from DocumentStoreOptions — replaced by required IDatabaseProvider DatabaseProvider. The connection string is now passed to each provider’s constructorDI extensions bundled into each provider package — no separate
Shiny.SqliteDocumentDb.Extensions.DependencyInjection packageSqliteDocumentStore moved to Shiny.DocumentDb.Sqlite namespace. Base class is now DocumentStore in Shiny.DocumentDb Feature
SQL Server provider via
Shiny.DocumentDb.SqlServer with AddSqlServerDocumentStore DI extension Feature
MySQL provider via
Shiny.DocumentDb.MySql with AddMySqlDocumentStore DI extension Feature
PostgreSQL provider via
Shiny.DocumentDb.PostgreSql with AddPostgreSqlDocumentStore DI extension Feature
Provider-agnostic
IDatabaseProvider interface — swap database backends without changing application code2.0 - March 22, 2026
Section titled “2.0 - March 22, 2026”DI extensions moved to separate
Shiny.SqliteDocumentDb.Extensions.DependencyInjection package — the core library no longer depends on Microsoft.Extensions.DependencyInjection.Abstractions Feature
Convenience constructor —
new SqliteDocumentStore("Data Source=mydata.db") for quick setup without options Feature
Configurable default table name via
DocumentStoreOptions.TableName (defaults to "documents") Feature
Table-per-type mapping —
MapTypeToTable<T>() gives a document type its own dedicated SQLite table with lazy creation on first use Feature
Auto-derived or explicit table names —
MapTypeToTable<T>() derives from the type name, MapTypeToTable<T>(string) uses an explicit name Feature
Duplicate table name protection — mapping two types to the same custom table throws
InvalidOperationException Feature
Custom Id property mapping —
MapTypeToTable<T>("table", x => x.MyProperty) uses an alternate property as the document Id instead of the default Id Feature
Fluent options API — all
MapTypeToTable overloads return DocumentStoreOptions for chaining Feature
Document diffing via
GetDiff<T>(id, modified) — compares a modified object against the stored document and returns an RFC 6902 JsonPatchDocument<T> with deep nested-object diffing powered by SystemTextJsonPatch Feature
All new features are fully AOT-safe — type names and Id property names are resolved at registration time, not at runtime
Feature
Batch insert via
BatchInsert<T>(IEnumerable<T>) — inserts a collection in a single transaction with prepared command reuse, auto-generates IDs, and rolls back atomically on failure1.0 - March 6, 2026
Section titled “1.0 - March 6, 2026” Feature
Schema-free JSON document storage on top of SQLite
Feature
Mandatory typed
Id property on document types (Guid, int, long, or string) — stored in both the SQLite column and the JSON blob so query results always include it Feature
Auto-generation of Ids on Insert:
Guid → Guid.NewGuid(), int/long → MAX(CAST(Id AS INTEGER)) + 1 per TypeName. String Ids must be set explicitly — Insert throws for default string Ids Feature
LINQ expression queries translated to json_extract SQL with support for equality, comparisons, logical operators, null checks, string methods, nested properties, and collection queries
Feature
Fluent query builder (IDocumentQuery) — chain .Where(), .OrderBy(), .OrderByDescending(), .GroupBy(), .Paginate(), .Select() and terminate with .ToList(), .ToAsyncEnumerable(), .Count(), .Any(), .ExecuteDelete(), .ExecuteUpdate(), .Max(), .Min(), .Sum(), .Average()
Feature
Pagination via .Paginate(offset, take) — translates to SQL LIMIT/OFFSET
Feature
Expression-based ordering — .OrderBy(u => u.Age) and .OrderByDescending(u => u.Name) on the fluent query builder
Feature
SQL-level projections via .Select() using json_object for extracting specific fields without full deserialization
Feature
IAsyncEnumerable streaming via .ToAsyncEnumerable() — yield results one-at-a-time without buffering
Feature
Expression-based JSON indexes for up to 30x faster queries on indexed properties
Feature
Full AOT and trimming support — all JsonTypeInfo parameters are optional and auto-resolve from configured JsonSerializerContext
Feature
Scalar aggregates: .Max(), .Min(), .Sum(), .Average() as terminal methods on the query builder
Feature
Aggregate projections with automatic GROUP BY via Sql.Count(), Sql.Max(), Sql.Min(), Sql.Sum(), Sql.Avg() marker methods
Feature
Collection-level aggregates in projections: Sum, Min, Max, Average on child collections (e.g. o.Lines.Sum(l => l.Quantity))
Feature
Explicit Insert / Update / Upsert API — Insert throws on duplicate Ids, Update throws if not found, Upsert deep-merges via json_patch
Feature
SetProperty — update a single scalar JSON field via json_set without deserializing the document. Supports nested paths
Feature
RemoveProperty — strip a field from the stored JSON via json_remove. Works on any property type
Feature
Typed Id lookups — Get, Remove, SetProperty, and RemoveProperty accept the Id as
object (Guid, int, long, or string). Unsupported types throw ArgumentException Feature
Bulk delete via query builder — .Where(predicate).ExecuteDelete() returns count of deleted documents
Feature
Bulk update via query builder — .Where(predicate).ExecuteUpdate(property, value) updates a property on matching documents via json_set() and returns count updated
Feature
Transactions with automatic commit/rollback via RunInTransaction
Feature
Hot backup via store.Backup(path) — copies the database to a file using the SQLite Online Backup API while the store remains usable
Feature
Dependency injection registration via AddSqliteDocumentStore
Feature
Configurable type name resolution (ShortName or FullName)
Feature
UseReflectionFallback option for strict AOT enforcement
Feature
SQL logging callback via DocumentStoreOptions.Logging
Feature
Raw SQL query and streaming support via store.Query(whereClause) and store.QueryStream(whereClause)