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

3.4 KiB

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
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