db.count(entity, opts) returns just the number of matching rows. Use it for pagination totals, badge counts, and quick checks where you don't need the data itself. Same filter vocabulary as list.
db.count(entity, opts) returns a Promise<number>. opts accepts the same filters as list — sort, pagination, and projection are ignored (they can't change the count).db.countSync(entity, opts) is the synchronous version for the in-memory backend.count walks the index. Otherwise it walks the data and counts matches — same cost as list(...).length but without allocating an array.count(opts) === list(opts).length always.
flowchart LR
A["count(entity, opts)"] --> I{index
available?}
I -- yes --> IX[Index scan] --> N[count]
I -- no --> DS[Data scan] --> N
B["list(entity, opts)"] --> DS2[Data scan] --> Arr[array of rows] --> L["arr.length"]
L -. should equal .- N
style N fill:#c8e6c9,stroke:#2e7d32
style L fill:#fff3e0,stroke:#ef6c00
Seed 50 products. Products have a random price and a category chosen round-robin from 5 categories (so 10 electronics, 10 books, etc.).Count all — reads 50.Count (price > 50) and Count (electronics) — the counter updates with the filtered count and the label explains what was counted.Verify count vs list — runs both queries and shows that count(opts) and list(opts).length agree.50 products with random price (0–100) and a category cycling through electronics, books, clothing, food, toys (10 of each).
Build any filter and see its count. Value can be a string, a number (auto-detected), true/false, or empty for null operators.
Confirms that count(opts) and list(opts).length always agree for the same options.
Run all tests seeds 50 rows into count_test and runs these 6 checks:
count(price > 50) matches list(...) lengthcount(category = "electronics") returns 10 (seed is deterministic)price > 20 AND category = "books") matches list lengthcountSync returns the same number as countcount on an empty entity returns 0