Files
MultiforaDB/tests/spec/indexes/README.md
A.Shakhmatov 55009a429d plan/spec: partial indexes are done, hashed is next
partial.json 3/24 -> 24/24, hashed.json still 0/18. PLAN §6 records the
planner rule that is deliberately left conservative -- a partial index is
maintained and enforces `unique`, and reads scan until the implication test
exists.

Full matrix at this commit: 250/250 unit tests in ReleaseFast and ReleaseSafe,
83/83 fuzz, operators 125/0, positional 51/0, aggregation 70/0, pinned crud
228/63/196, e2e and crash-fuzz green.
2026-08-10 22:51:38 +03:00

81 lines
3.4 KiB
Markdown

# The index corpus
M3's last row: partial and hashed indexes. `docs/M3_INDEX_TYPES_DESIGN_REVIEW.md`
measured both against mongod 8.3.7 and found they were not the same kind of
gap — hashed was honestly refused, `partialFilterExpression` was accepted and
ignored, and a *unique* partial index therefore refused inserts mongod
accepts.
It also found that **no test in this repository covered that row, in any
suite**. The pinned corpus is crud and aggregate; `tests/e2e/e2e5.js` and
`e2e6.js` test indexes and write neither a partial nor a hashed spec. So this
directory exists for the same reason `tests/spec/positional/` and
`tests/spec/operators/` do.
## The one rule
**Inputs are authored here; expectations are measured against a real mongod.**
```
tests/spec/indexes/
sources/*.json documents + operations, authored
record.js runs them against mongod, writes the expectations
*.json generated, unified format, do not hand-edit
```
```sh
mongod --port 27099 --dbpath <dir>
node tests/spec/indexes/record.js --mongod-port 27099
node tests/spec/run.js --suite-dir tests/spec/indexes
```
Unlike the other two corpora, a case here is a **sequence**: create an index,
insert against it, read back, list it. An index outlives a `deleteMany`, and
every case is about which indexes exist, so the recorder drops the collection
between cases and walks each case's operations in order — stopping at the
first that throws, which is what a client would see.
## Where it stands
Recorded against mongod 8.3.7 at 3/39 -- red by construction -- and partial
indexes have since been driven green:
```
hashed.json 0 pass 18 fail 0 skip
partial.json 24 pass 0 fail 0 skip
```
The three that passed at the start were the reads a partial index does not
change: this server indexed every document, so a query still found
everything, which is the whole reason the review called the partial gap
smaller than the `arrayFilters` one.
## What recording it settled
Two of the review's own guesses were wrong, which is why it was recorded
rather than reasoned:
| | mongod |
|---|---|
| `$in` in a partial filter | **allowed** — the review listed it with `$ne` and `$regex` |
| same key, different filter, no explicit name | **IndexKeySpecsConflict (86)**, not the 67 the review assumed |
And what it confirmed:
| | mongod |
|---|---|
| a unique partial index | constrains only the documents its filter selects — two `{a: 1, t: false}` are fine, two `{a: 9, t: true}` are E11000 |
| a document *leaving* the filter | frees the value it held for another document to take |
| a document *entering* the filter | must take a value nothing inside it holds, or the update is E11000 |
| `$regex`, `$ne` in a filter | 67 |
| a filter that is not a document | TypeMismatch (14) |
| `sparse` + `partialFilterExpression` | 67 — may not be combined |
| `expireAfterSeconds` + a filter | allowed; `listIndexes` reports the filter *before* the expiry |
| an empty filter | allowed, and reported |
| two hashed components | 31303 |
| `unique` on a hashed index | 16764 |
| an array at a hashed path | 16766, **at insert time**, not at creation |
| a key direction that is not 1, -1 or `"hashed"` | 67 |
| a hashed index beside an ascending one on the same field | both exist |
| a range query or a sort over a hashed field | still correct — the planner declines the index rather than misusing it |