M3's last row, and the first of the four corpora here whose subject nothing in
the repository tested at all: the pinned suite is crud and aggregate, and
`e2e5.js`/`e2e6.js` write neither a partial nor a hashed spec.
42 cases in two files, recorded red at 3/39. The three that pass are the reads
a partial index does not change -- this server indexes every document, so a
query still finds everything, which is exactly why the review called this a
smaller fire than `arrayFilters`.
A case here is a *sequence* rather than one operation: create an index, insert
against it, read back, list it. So the recorder walks a case's operations in
order and stops at the first that throws, which is what a client would see,
and drops the collection between cases because an index outlives a
`deleteMany`.
Two of the design review's own guesses were wrong, which is the argument for
recording rather than reasoning:
- **`$in` in a partial filter is allowed.** The review grouped it with `$ne`
and `$regex`, which are 67.
- **Same key, different filter, no explicit name is IndexKeySpecsConflict
(86)**, not the 67 the review assumed.
What it confirmed, and what the implementation now has to satisfy: a unique
partial index constrains only the documents its filter selects; a document
*leaving* the filter frees the value it held; a document *entering* it must
take a value nothing inside holds, or the update is E11000. `sparse` and
`partialFilterExpression` may not be combined (67). `expireAfterSeconds` and a
filter may, and `listIndexes` reports the filter before the expiry. Two hashed
components is 31303, `unique` on a hashed index is 16764, and an array at a
hashed path is 16766 *at insert time* rather than at creation.
194 lines
8.3 KiB
JSON
194 lines
8.3 KiB
JSON
{
|
|
"_comment": [
|
|
"Inputs only. Expectations are measured -- see record.js.",
|
|
"`partialFilterExpression`: which filters may be written, what the index",
|
|
"then reports about itself, and the one behaviour that made ignoring the",
|
|
"option a wrong answer rather than a missing feature -- a unique partial",
|
|
"index constrains only the documents its filter selects."
|
|
],
|
|
"documents": [
|
|
{ "_id": 1, "a": 1, "s": "x" },
|
|
{ "_id": 2, "a": 5, "s": "y" },
|
|
{ "_id": 3, "s": "z" },
|
|
{ "_id": 4, "a": 5, "s": "x" }
|
|
],
|
|
"cases": [
|
|
{
|
|
"description": "a partial index is created and reports its filter",
|
|
"ops": [
|
|
{ "name": "createIndex", "arguments": { "keys": { "a": 1 }, "partialFilterExpression": { "a": { "$gte": 5 } } } },
|
|
{ "name": "listIndexes", "arguments": {} }
|
|
]
|
|
},
|
|
{
|
|
"description": "a query the filter covers still answers every match",
|
|
"ops": [
|
|
{ "name": "createIndex", "arguments": { "keys": { "a": 1 }, "partialFilterExpression": { "a": { "$gte": 5 } } } },
|
|
{ "name": "find", "arguments": { "filter": { "a": { "$gte": 5 } }, "sort": { "_id": 1 } } }
|
|
]
|
|
},
|
|
{
|
|
"description": "a query the filter excludes still answers every match",
|
|
"ops": [
|
|
{ "name": "createIndex", "arguments": { "keys": { "a": 1 }, "partialFilterExpression": { "a": { "$gte": 5 } } } },
|
|
{ "name": "find", "arguments": { "filter": { "a": 1 }, "sort": { "_id": 1 } } }
|
|
]
|
|
},
|
|
{
|
|
"description": "a query straddling the filter still answers every match",
|
|
"ops": [
|
|
{ "name": "createIndex", "arguments": { "keys": { "a": 1 }, "partialFilterExpression": { "a": { "$gte": 5 } } } },
|
|
{ "name": "find", "arguments": { "filter": { "a": { "$gte": 1 } }, "sort": { "_id": 1 } } },
|
|
{ "name": "countDocuments", "arguments": { "filter": {} } }
|
|
]
|
|
},
|
|
{
|
|
"description": "a unique partial index accepts duplicates its filter excludes",
|
|
"documents": [],
|
|
"ops": [
|
|
{ "name": "createIndex", "arguments": { "keys": { "a": 1 }, "unique": true, "partialFilterExpression": { "t": true } } },
|
|
{ "name": "insertMany", "arguments": { "documents": [{ "_id": 1, "a": 1, "t": false }, { "_id": 2, "a": 1, "t": false }] } },
|
|
{ "name": "find", "arguments": { "filter": {}, "sort": { "_id": 1 } } }
|
|
]
|
|
},
|
|
{
|
|
"description": "a unique partial index refuses duplicates its filter selects",
|
|
"documents": [],
|
|
"ops": [
|
|
{ "name": "createIndex", "arguments": { "keys": { "a": 1 }, "unique": true, "partialFilterExpression": { "t": true } } },
|
|
{ "name": "insertMany", "arguments": { "documents": [{ "_id": 1, "a": 9, "t": true }, { "_id": 2, "a": 9, "t": true }] } }
|
|
]
|
|
},
|
|
{
|
|
"description": "a document leaving the filter frees the value it held",
|
|
"documents": [],
|
|
"ops": [
|
|
{ "name": "createIndex", "arguments": { "keys": { "a": 1 }, "unique": true, "partialFilterExpression": { "t": true } } },
|
|
{ "name": "insertMany", "arguments": { "documents": [{ "_id": 1, "a": 9, "t": true }] } },
|
|
{ "name": "updateOne", "arguments": { "filter": { "_id": 1 }, "update": { "$set": { "t": false } } } },
|
|
{ "name": "insertOne", "arguments": { "document": { "_id": 2, "a": 9, "t": true } } },
|
|
{ "name": "find", "arguments": { "filter": {}, "sort": { "_id": 1 } } }
|
|
]
|
|
},
|
|
{
|
|
"description": "a document entering the filter takes the value it names",
|
|
"documents": [],
|
|
"ops": [
|
|
{ "name": "createIndex", "arguments": { "keys": { "a": 1 }, "unique": true, "partialFilterExpression": { "t": true } } },
|
|
{ "name": "insertMany", "arguments": { "documents": [{ "_id": 1, "a": 9, "t": true }, { "_id": 2, "a": 9, "t": false }] } },
|
|
{ "name": "updateOne", "arguments": { "filter": { "_id": 2 }, "update": { "$set": { "t": true } } } }
|
|
]
|
|
},
|
|
{
|
|
"description": "a filter on $exists",
|
|
"ops": [
|
|
{ "name": "createIndex", "arguments": { "keys": { "a": 1 }, "partialFilterExpression": { "a": { "$exists": true } } } },
|
|
{ "name": "listIndexes", "arguments": {} }
|
|
]
|
|
},
|
|
{
|
|
"description": "a filter with two predicates",
|
|
"ops": [
|
|
{ "name": "createIndex", "arguments": { "keys": { "a": 1 }, "partialFilterExpression": { "a": { "$gt": 0 }, "s": "x" } } },
|
|
{ "name": "listIndexes", "arguments": {} }
|
|
]
|
|
},
|
|
{
|
|
"description": "a filter with an explicit $and",
|
|
"ops": [
|
|
{ "name": "createIndex", "arguments": { "keys": { "a": 1 }, "partialFilterExpression": { "$and": [{ "a": { "$gt": 0 } }] } } },
|
|
{ "name": "listIndexes", "arguments": {} }
|
|
]
|
|
},
|
|
{
|
|
"description": "a filter on a field the index does not name",
|
|
"ops": [
|
|
{ "name": "createIndex", "arguments": { "keys": { "a": 1 }, "partialFilterExpression": { "s": "x" } } },
|
|
{ "name": "listIndexes", "arguments": {} }
|
|
]
|
|
},
|
|
{
|
|
"description": "a filter using $regex is refused",
|
|
"ops": [
|
|
{ "name": "createIndex", "arguments": { "keys": { "a": 1 }, "partialFilterExpression": { "s": { "$regex": "x" } } } }
|
|
]
|
|
},
|
|
{
|
|
"description": "a filter using $ne is refused",
|
|
"ops": [
|
|
{ "name": "createIndex", "arguments": { "keys": { "a": 1 }, "partialFilterExpression": { "a": { "$ne": 1 } } } }
|
|
]
|
|
},
|
|
{
|
|
"description": "a filter using $in is refused",
|
|
"ops": [
|
|
{ "name": "createIndex", "arguments": { "keys": { "a": 1 }, "partialFilterExpression": { "a": { "$in": [1, 2] } } } }
|
|
]
|
|
},
|
|
{
|
|
"description": "a filter that is not a document is refused",
|
|
"ops": [
|
|
{ "name": "createIndex", "arguments": { "keys": { "a": 1 }, "partialFilterExpression": 1 } }
|
|
]
|
|
},
|
|
{
|
|
"description": "an empty filter",
|
|
"ops": [
|
|
{ "name": "createIndex", "arguments": { "keys": { "a": 1 }, "partialFilterExpression": {} } },
|
|
{ "name": "listIndexes", "arguments": {} }
|
|
]
|
|
},
|
|
{
|
|
"description": "sparse and a partial filter may not be combined",
|
|
"ops": [
|
|
{ "name": "createIndex", "arguments": { "keys": { "a": 1 }, "sparse": true, "partialFilterExpression": { "a": { "$gt": 0 } } } }
|
|
]
|
|
},
|
|
{
|
|
"description": "a partial filter with a TTL",
|
|
"ops": [
|
|
{ "name": "createIndex", "arguments": { "keys": { "a": 1 }, "expireAfterSeconds": 100, "partialFilterExpression": { "a": { "$gt": 0 } } } },
|
|
{ "name": "listIndexes", "arguments": {} }
|
|
]
|
|
},
|
|
{
|
|
"description": "a partial index on a compound key",
|
|
"ops": [
|
|
{ "name": "createIndex", "arguments": { "keys": { "a": 1, "s": 1 }, "partialFilterExpression": { "a": { "$gt": 0 } } } },
|
|
{ "name": "listIndexes", "arguments": {} }
|
|
]
|
|
},
|
|
{
|
|
"description": "two indexes on one key differing only in their filter",
|
|
"ops": [
|
|
{ "name": "createIndex", "arguments": { "keys": { "a": 1 }, "name": "one", "partialFilterExpression": { "a": { "$gt": 0 } } } },
|
|
{ "name": "createIndex", "arguments": { "keys": { "a": 1 }, "name": "two", "partialFilterExpression": { "a": { "$gt": 4 } } } },
|
|
{ "name": "listIndexes", "arguments": {} }
|
|
]
|
|
},
|
|
{
|
|
"description": "the same index twice is idempotent",
|
|
"ops": [
|
|
{ "name": "createIndex", "arguments": { "keys": { "a": 1 }, "partialFilterExpression": { "a": { "$gt": 0 } } } },
|
|
{ "name": "createIndex", "arguments": { "keys": { "a": 1 }, "partialFilterExpression": { "a": { "$gt": 0 } } } },
|
|
{ "name": "listIndexes", "arguments": {} }
|
|
]
|
|
},
|
|
{
|
|
"description": "the same name with a different filter conflicts",
|
|
"ops": [
|
|
{ "name": "createIndex", "arguments": { "keys": { "a": 1 }, "partialFilterExpression": { "a": { "$gt": 0 } } } },
|
|
{ "name": "createIndex", "arguments": { "keys": { "a": 1 }, "partialFilterExpression": { "a": { "$gt": 4 } } } }
|
|
]
|
|
},
|
|
{
|
|
"description": "a partial index is dropped by name",
|
|
"ops": [
|
|
{ "name": "createIndex", "arguments": { "keys": { "a": 1 }, "name": "pa", "partialFilterExpression": { "a": { "$gt": 0 } } } },
|
|
{ "name": "dropIndex", "arguments": { "name": "pa" } },
|
|
{ "name": "listIndexes", "arguments": {} }
|
|
]
|
|
}
|
|
]
|
|
}
|