MongoDB Compatibility Matrix
Version: 1.0
Baseline: MongoDB 6.0+ Wire Protocol
Last Updated: 2026-03-04
Token Inventory: 308 tokens across 6 categories (from tests/e2e/matrix/mql_language/reference_tokens.py)
Thermocline targets compatibility with the MongoDB 6.0+ wire protocol and MQL surface. Applications connect using standard MongoDB drivers with only a connection string change.
This document provides a per-operator compatibility matrix across three execution tiers:
| Tier | Description |
|---|
| Hot (SE) | Storage Engine (Rust) -- native LSM-tree, in-memory evaluation |
| Cold (QE) | Query Engine (Rust) -- Parquet/DataFusion, cold-tier pushdown |
| Federated | Coordinator (Go) -- hot+cold merge, post-filter materialization |
Legend
| Symbol | Meaning |
|---|
| Y | Fully supported |
| P | Partial support (see Notes) |
| N | Not supported |
| -- | Not applicable to this tier |
| RT | Routed through another tier (e.g., geo queries routed through SE materialization) |
1. Query Operators (31 tokens)
All query predicate operators used in find(), $match, deleteMany(), updateMany(), etc.
| Operator | Hot (SE) | Cold (QE) | Federated | Notes |
|---|
$eq | Y | Y | Y | Implicit equality and explicit {$eq: val} |
$ne | Y | Y | Y | Fixed in E5-S1 |
$gt | Y | Y | Y | |
$gte | Y | Y | Y | |
$lt | Y | Y | Y | |
$lte | Y | Y | Y | |
$in | Y | Y | Y | |
$nin | Y | Y | Y | QE: post-filter path (E5-S3) |
$and | Y | Y | Y | |
$or | Y | Y | Y | |
$not | Y | Y | Y | Per-field negation |
$nor | Y | Y | Y | |
$exists | Y | Y | Y | |
$type | Y | P | Y | QE: limited without schema; SE post-filter fallback (E5-S2) |
$regex | Y | P | Y | QE: post-filter for complex patterns (E5-S3) |
$mod | Y | P | Y | QE: post-filter path |
$expr | Y | N | RT | Aggregation expression in filter; cold uses SE materialization |
$text | Y | Y | Y | Requires text index; QE has dedicated text index module |
$where | Y | N | RT | JS expression evaluation; cold routed through SE |
$all | Y | P | Y | QE: post-filter for array containment |
$elemMatch | Y | P | Y | QE: equality pushdown; range on LIST columns uses post-filter (E5-S3) |
$size | Y | P | Y | QE: post-filter path |
$bitsAllSet | Y | P | Y | QE: post-filter path |
$bitsAllClear | Y | P | Y | QE: post-filter path |
$bitsAnySet | Y | P | Y | QE: post-filter path |
$bitsAnyClear | Y | P | Y | QE: post-filter path |
$geoWithin | Y | N | RT | QE: routed through SE materialization (E5-S7) |
$geoIntersects | Y | N | RT | QE: routed through SE materialization (E5-S7) |
$near | Y | N | RT | QE: routed through SE materialization (E5-S7) |
$nearSphere | Y | N | RT | QE: routed through SE materialization (E5-S7) |
$jsonSchema | Y | N | RT | Schema validation in query context |
Coverage: 31/31 tokens handled (all routed or supported across tiers)
2. Update Operators (23 tokens)
Update operators are SE-only (writes always go to the hot tier).
| Operator | Hot (SE) | Cold (QE) | Federated | Notes |
|---|
$set | Y | -- | -- | |
$unset | Y | -- | -- | |
$inc | Y | -- | -- | |
$mul | Y | -- | -- | |
$min | Y | -- | -- | |
$max | Y | -- | -- | |
$rename | Y | -- | -- | |
$currentDate | Y | -- | -- | Supports {$type: "date"} and {$type: "timestamp"} |
$setOnInsert | Y | -- | -- | Applied only during upsert insert |
$push | Y | -- | -- | With $each, $position, $slice, $sort modifiers |
$addToSet | Y | -- | -- | With $each modifier |
$pull | Y | -- | -- | Supports query condition matching |
$pullAll | Y | -- | -- | |
$pop | Y | -- | -- | First (-1) and last (1) element |
$bit | Y | -- | -- | and, or, xor bitwise operations |
$ (positional) | Y | -- | -- | Resolves to matched array index |
$[] (all positional) | P | -- | -- | Supported via resolve_positional for single $ |
$[<identifier>] (filtered) | P | -- | -- | Array filter identifier support is partial |
$each | Y | -- | -- | Modifier for $push and $addToSet |
$position | Y | -- | -- | Modifier for $push with $each |
$slice (update) | Y | -- | -- | Modifier for $push with $each |
$sort (update) | Y | -- | -- | Modifier for $push with $each |
Coverage: 23/23 tokens handled
3. Projection Operators (3 tokens)
| Operator | Hot (SE) | Cold (QE) | Federated | Notes |
|---|
$ (positional) | Y | -- | RT | Positional projection from query match |
$elemMatch | Y | -- | RT | Project first matching array element |
$slice | Y | -- | RT | Subset of array: {field: {$slice: N}} or {field: {$slice: [skip, limit]}} |
Additional projection features supported on SE:
- Inclusion/exclusion projection
_id exclusion with inclusion fields
$meta projection (textScore, indexKey, recordId, vectorSearchScore)
- Computed expressions in
$project (arithmetic, string, conditional, field refs)
- Nested field projection via dot notation
Coverage: 3/3 tokens handled
4. Aggregation Stages (51 tokens)
| Stage | Hot (SE) | Cold (QE) | Federated | Notes |
|---|
$match | Y | Y | Y | Delegates to filter evaluator |
$project | Y | Y | Y | Full expression support |
$sort | Y | Y | Y | |
$limit | Y | Y | Y | |
$skip | Y | Y | Y | |
$count | Y | Y | Y | |
$group | Y | P | Y | QE: basic aggregation via DataFusion; SE: 25 accumulators |
$addFields | Y | P | Y | SE: full expression eval; QE: literal/field-ref only |
$set | Y | P | Y | Alias for $addFields |
$unset | Y | P | Y | |
$unwind | Y | P | Y | With includeArrayIndex and preserveNullAndEmptyArrays |
$lookup | Y | N | RT | Equality and sub-pipeline forms; requires SE for foreign docs |
$facet | Y | N | RT | Multiple sub-pipelines |
$bucket | Y | N | RT | Boundary-based grouping with accumulators |
$bucketAuto | Y | N | RT | Auto-bucketing with granularity series (R5/R10/R20/R40/1-2-5/POWERSOF2) |
$sample | Y | N | RT | Random sampling |
$replaceRoot | Y | N | RT | Replace document with sub-expression |
$replaceWith | Y | N | RT | Alias for $replaceRoot |
$redact | Y | N | RT | Field-level access control ($$PRUNE/$$DESCEND/$$KEEP) |
$sortByCount | Y | N | RT | Group + count + sort descending |
$graphLookup | Y | N | RT | Recursive graph traversal with depth control |
$densify | Y | N | RT | Fill gaps in sequences (numeric/date) |
$fill | Y | N | RT | Fill missing values (value/LOCF/linear methods) |
$documents | Y | N | RT | Literal document stream |
$setWindowFields | Y | N | RT | Window functions with document/range bounds |
$unionWith | Y | N | RT | Combine with another collection's documents |
$geoNear | Y | N | RT | Distance computation and proximity sort |
$out | Y | N | RT | Write output to collection (parsed, execution deferred) |
$merge | Y | N | RT | Merge into collection (replace/keepExisting/merge/fail) |
$vectorSearch | Y | Y | Y | HNSW hot path + cold brute-force; coordinator merges results |
$changeStream | P | -- | P | Passthrough; WAL-based change streams handled at gateway/SE level |
$changeStreamSplitLargeEvent | P | -- | -- | Passthrough |
$collStats | P | -- | -- | Passthrough (returns collection statistics) |
$currentOp | P | -- | -- | Passthrough (server diagnostics) |
$indexStats | P | -- | -- | Passthrough (index usage statistics) |
$planCacheStats | P | -- | -- | Passthrough (plan cache diagnostics) |
$listSessions | P | -- | -- | Passthrough |
$listLocalSessions | P | -- | -- | Passthrough |
$listClusterCatalog | N | -- | -- | Atlas-specific; passthrough (no-op) |
$listSampledQueries | N | -- | -- | Atlas-specific; passthrough (no-op) |
$listSearchIndexes | N | -- | -- | Atlas Search; passthrough (no-op) |
$querySettings | N | -- | -- | Atlas-specific; passthrough (no-op) |
$queryStats | N | -- | -- | Atlas-specific; passthrough (no-op) |
$rankFusion | N | -- | -- | Atlas Search; passthrough (no-op) |
$score | N | -- | -- | Atlas Search; passthrough (no-op) |
$scoreFusion | N | -- | -- | Atlas Search; passthrough (no-op) |
$search | N | -- | -- | Atlas Search; passthrough (no-op) |
$searchMeta | N | -- | -- | Atlas Search; passthrough (no-op) |
$shardedDataDistribution | N | -- | -- | Sharded cluster diagnostic; passthrough (no-op) |
$mlTrain | Y | -- | -- | Thermocline extension: in-database ML training |
$mlPredict | Y | -- | -- | Thermocline extension: ML model prediction |
Coverage: 51/51 reference tokens parsed (30 fully implemented, 8 passthrough for server diagnostics, 13 Atlas/sharded-specific stubs)
5. Aggregation Expressions (182 tokens)
5.1 Arithmetic (42 tokens)
| Expression | Hot (SE) | Cold (QE) | Federated | Notes |
|---|
$add | Y | Y | Y | Multi-operand; date+number addition |
$subtract | Y | Y | Y | |
$multiply | Y | Y | Y | Multi-operand |
$divide | Y | Y | Y | Division by zero returns NaN |
$mod | Y | Y | Y | |
$abs | Y | Y | Y | |
$ceil | Y | Y | Y | |
$floor | Y | Y | Y | |
$round | Y | Y | Y | Optional precision argument |
$trunc | Y | Y | Y | Optional precision argument |
$pow | Y | P | Y | |
$sqrt | Y | P | Y | |
$log | Y | P | Y | |
$ln | Y | P | Y | |
$log10 | Y | P | Y | |
$exp | Y | P | Y | |
$rand | Y | N | RT | Random number generation |
$sampleRate | Y | N | RT | Probabilistic document sampling |
$sin | Y | P | Y | |
$cos | Y | P | Y | |
$tan | Y | P | Y | |
$asin | Y | P | Y | |
$acos | Y | P | Y | |
$atan | Y | P | Y | |
$atan2 | Y | P | Y | |
$sinh | Y | P | Y | |
$cosh | Y | P | Y | |
$tanh | Y | P | Y | |
$asinh | Y | P | Y | |
$acosh | Y | P | Y | |
$atanh | Y | P | Y | |
$degreesToRadians | Y | P | Y | |
$radiansToDegrees | Y | P | Y | |
$sigmoid | Y | N | RT | Thermocline extension |
$bitAnd | Y | N | RT | |
$bitOr | Y | N | RT | |
$bitXor | Y | N | RT | |
$bitNot | Y | N | RT | |
$binarySize | Y | N | RT | |
$bsonSize | Y | N | RT | |
$subtype | Y | N | RT | Binary subtype extraction |
$tsIncrement | Y | N | RT | Timestamp increment extraction |
$tsSecond | Y | N | RT | Timestamp seconds extraction |
5.2 String (22 tokens)
| Expression | Hot (SE) | Cold (QE) | Federated | Notes |
|---|
$concat | Y | Y | Y | |
$toUpper | Y | Y | Y | |
$toLower | Y | Y | Y | |
$substr | Y | Y | Y | Alias for $substrCP |
$substrCP | Y | Y | Y | Code-point based substring |
$substrBytes | Y | P | Y | Byte-based substring |
$trim | Y | P | Y | |
$ltrim | Y | P | Y | |
$rtrim | Y | P | Y | |
$split | Y | P | Y | |
$strLenCP | Y | P | Y | |
$strLenBytes | Y | P | Y | |
$indexOfCP | Y | P | Y | |
$indexOfBytes | Y | P | Y | |
$strcasecmp | Y | P | Y | |
$regexMatch | Y | P | Y | |
$regexFind | Y | P | Y | |
$regexFindAll | Y | P | Y | |
$replaceOne | Y | P | Y | |
$replaceAll | Y | P | Y | |
$encStrContains | Y | N | RT | Encrypted string operations |
$encStrEndsWith | Y | N | RT | Encrypted string operations |
$encStrStartsWith | Y | N | RT | Encrypted string operations |
$encStrNormalizedEq | Y | N | RT | Encrypted string operations |
5.3 Date (17 tokens)
| Expression | Hot (SE) | Cold (QE) | Federated | Notes |
|---|
$year | Y | Y | Y | |
$month | Y | Y | Y | |
$dayOfMonth | Y | Y | Y | |
$dayOfWeek | Y | Y | Y | |
$dayOfYear | Y | Y | Y | |
$hour | Y | Y | Y | |
$minute | Y | Y | Y | |
$second | Y | Y | Y | |
$millisecond | Y | Y | Y | |
$week | Y | Y | Y | |
$isoWeek | Y | Y | Y | QE: dedicated UDF |
$isoWeekYear | Y | Y | Y | QE: dedicated UDF |
$isoDayOfWeek | Y | Y | Y | |
$dateToString | Y | P | Y | |
$dateFromString | Y | P | Y | |
$dateTrunc | Y | P | Y | |
$dateAdd | Y | P | Y | |
$dateSubtract | Y | P | Y | |
$dateDiff | Y | P | Y | |
$dateFromParts | Y | P | Y | |
$dateToParts | Y | P | Y | |
5.4 Conditional (3 tokens)
| Expression | Hot (SE) | Cold (QE) | Federated | Notes |
|---|
$cond | Y | Y | Y | If-then-else |
$ifNull | Y | Y | Y | |
$switch | Y | P | Y | |
5.5 Comparison (7 tokens)
| Expression | Hot (SE) | Cold (QE) | Federated | Notes |
|---|
$cmp | Y | P | Y | |
$eq | Y | Y | Y | Expression-level equality |
$ne | Y | Y | Y | |
$gt | Y | Y | Y | |
$gte | Y | Y | Y | |
$lt | Y | Y | Y | |
$lte | Y | Y | Y | |
5.6 Logical (3 tokens)
| Expression | Hot (SE) | Cold (QE) | Federated | Notes |
|---|
$and | Y | Y | Y | |
$or | Y | Y | Y | |
$not | Y | Y | Y | |
5.7 Type (15 tokens)
| Expression | Hot (SE) | Cold (QE) | Federated | Notes |
|---|
$type | Y | P | Y | |
$convert | Y | Y | Y | QE: dedicated ConvertWithErrorUdf |
$toBool | Y | P | Y | |
$toInt | Y | P | Y | |
$toLong | Y | P | Y | |
$toDouble | Y | P | Y | |
$toDecimal | Y | P | Y | |
$toString | Y | P | Y | |
$toObjectId | Y | Y | Y | QE: dedicated ToObjectIdUdf |
$toDate | Y | P | Y | |
$toUUID | Y | N | RT | |
$toHashedIndexKey | Y | N | RT | |
$serializeEJSON | Y | N | RT | |
$deserializeEJSON | Y | N | RT | |
$isNumber | Y | P | Y | |
$isArray | Y | P | Y | |
5.8 Array (25 tokens)
| Expression | Hot (SE) | Cold (QE) | Federated | Notes |
|---|
$arrayElemAt | Y | Y | Y | QE: dedicated array UDF |
$concatArrays | Y | P | Y | |
$filter | Y | P | Y | Variable binding ($$this, as) |
$in | Y | P | Y | |
$size | Y | P | Y | |
$slice | Y | P | Y | |
$map | Y | P | Y | Variable binding |
$reduce | Y | N | RT | |
$zip | Y | N | RT | |
$first | Y | P | Y | |
$last | Y | P | Y | |
$firstN | Y | N | RT | |
$lastN | Y | N | RT | |
$maxN | Y | N | RT | |
$minN | Y | N | RT | |
$reverseArray | Y | N | RT | |
$range | Y | N | RT | |
$indexOfArray | Y | N | RT | |
$sortArray | Y | N | RT | |
$setEquals | Y | Y | Y | QE: dedicated set UDF |
$setIntersection | Y | Y | Y | QE: dedicated set UDF |
$setUnion | Y | Y | Y | QE: dedicated set UDF |
$setDifference | Y | Y | Y | QE: dedicated set UDF |
$setIsSubset | Y | Y | Y | QE: dedicated set UDF |
$anyElementTrue | Y | Y | Y | QE: dedicated set UDF |
$allElementsTrue | Y | Y | Y | QE: dedicated set UDF |
$arrayToObject | Y | P | Y | |
$objectToArray | Y | P | Y | |
5.9 Object (5 tokens)
| Expression | Hot (SE) | Cold (QE) | Federated | Notes |
|---|
$mergeObjects | Y | Y | Y | QE: dedicated object UDF |
$objectToArray | Y | P | Y | |
$arrayToObject | Y | P | Y | |
$getField | Y | Y | Y | QE: dedicated object UDF |
$setField | Y | N | RT | |
$unsetField | Y | N | RT | |
5.10 Variable Binding and Custom Code (3 tokens)
| Expression | Hot (SE) | Cold (QE) | Federated | Notes |
|---|
$let | Y | N | RT | Variable binding for sub-expressions |
$literal | Y | Y | Y | Pass-through literal value |
$function | P | N | RT | Custom JS: evaluates first arg only (no server-side JS engine) |
$accumulator | P | N | RT | Custom accumulator: falls back to $sum with input field (no server-side JS) |
5.11 Window/Positional (8 tokens)
| Expression | Hot (SE) | Cold (QE) | Federated | Notes |
|---|
$rank | Y | N | RT | Window function in $setWindowFields |
$denseRank | Y | N | RT | Window function |
$documentNumber | Y | N | RT | Window function |
$shift | Y | N | RT | Window function with offset |
$expMovingAvg | Y | N | RT | Window function; passthrough in expression context |
$derivative | P | N | RT | Passthrough in expression context |
$integral | P | N | RT | Passthrough in expression context |
$linearFill | P | N | RT | Passthrough in expression context |
$locf | P | N | RT | Passthrough in expression context |
$minMaxScaler | Y | N | RT | Thermocline extension |
| Expression | Hot (SE) | Cold (QE) | Federated | Notes |
|---|
$meta | Y | P | Y | textScore, indexKey, recordId, vectorSearchScore |
5.13 Accumulator Expressions in Expression Context (8 tokens)
These work on arrays when used outside $group:
| Expression | Hot (SE) | Cold (QE) | Federated | Notes |
|---|
$sum | Y | Y | Y | |
$avg | Y | Y | Y | |
$min | Y | Y | Y | |
$max | Y | Y | Y | |
$push | Y | N | RT | |
$addToSet | Y | N | RT | |
$stdDevPop | Y | N | RT | |
$stdDevSamp | Y | N | RT | |
$covariancePop | Y | N | RT | |
$covarianceSamp | Y | N | RT | |
Coverage: 182/182 reference expression tokens handled (all implemented on SE; QE coverage via DataFusion UDFs + post-filter routing)
6. Accumulators ($group context) (25 tokens)
| Accumulator | Hot (SE) | Cold (QE) | Federated | Notes |
|---|
$sum | Y | Y | Y | Count mode with {$sum: 1} |
$avg | Y | Y | Y | |
$min | Y | Y | Y | |
$max | Y | Y | Y | |
$first | Y | P | Y | |
$last | Y | P | Y | |
$push | Y | N | RT | |
$addToSet | Y | N | RT | |
$concatArrays | Y | N | RT | Concatenate arrays across group |
$setUnion | Y | N | RT | Union arrays across group |
$count | Y | Y | Y | Shorthand for {$sum: 1} |
$stdDevPop | Y | N | RT | Population standard deviation (Welford's) |
$stdDevSamp | Y | N | RT | Sample standard deviation (Bessel's correction) |
$top | Y | N | RT | Top document by sort order |
$topN | Y | N | RT | Top N documents by sort order |
$bottom | Y | N | RT | Bottom document by sort order |
$bottomN | Y | N | RT | Bottom N documents by sort order |
$firstN | Y | N | RT | First N values in group |
$lastN | Y | N | RT | Last N values in group |
$maxN | Y | N | RT | N largest values |
$minN | Y | N | RT | N smallest values |
$mergeObjects | Y | N | RT | Merge documents in group |
$median | Y | N | RT | Median of numeric values |
$percentile | Y | N | RT | Percentile(s) of numeric values |
$accumulator | P | N | RT | Custom JS accumulator; falls back to $sum with input (no JS engine) |
Coverage: 25/25 reference accumulator tokens handled
7. Cross-Cutting Features
7.1 Collation
| Feature | Hot (SE) | Cold (QE) | Federated | Notes |
|---|
| Collation-aware queries | Y | N | RT | QE rejects collation; coordinator routes collated queries through SE (E5-S4) |
7.2 ACID Transactions
| Feature | Status | Notes |
|---|
| Multi-document transactions | Y | MVCC snapshot isolation |
readConcern levels | Y | local, majority, snapshot, linearizable |
writeConcern levels | Y | w:1, w:majority |
readPreference | Y | primary, secondary, secondaryPreferred, nearest |
atClusterTime (time travel) | Y | MVCC versioning |
7.3 Change Streams
| Feature | Status | Notes |
|---|
| Collection-level change streams | Y | WAL-based, guaranteed order |
| Database-level change streams | Y | |
| Resume tokens | Y | postBatchResumeToken in $clusterTime response |
fullDocument: "updateLookup" | Y | |
7.4 Vector Search
| Feature | Status | Notes |
|---|
$vectorSearch stage | Y | Hot: HNSW index; Cold: brute-force scan |
| Hybrid search (pre/post filter) | Y | Auto-strategy based on selectivity |
| Score normalization | Y | $meta: "vectorSearchScore" |
| SQ8 quantization | Y | 4x memory reduction with re-ranking |
7.5 Geospatial
| Feature | Hot (SE) | Cold (QE) | Notes |
|---|
2dsphere index | Y | N | |
$geoWithin | Y | N | GeoJSON and legacy coordinate pairs |
$geoIntersects | Y | N | GeoJSON geometries |
$near / $nearSphere | Y | N | Haversine distance |
$geoNear stage | Y | N | Distance computation with sort |
7.6 Text Search
| Feature | Hot (SE) | Cold (QE) | Notes |
|---|
| Text index | Y | Y | QE has dedicated text index module |
$text query operator | Y | Y | With language, case/diacritic sensitivity |
$meta: "textScore" | Y | Y | Relevance scoring |
8. Known Limitations and Out-of-Scope Items
8.1 Atlas Search Features (Not Applicable)
The following are Atlas Search / Atlas-specific features that are not part of the MongoDB server wire protocol. They are parsed as passthrough stages and return no-op results:
$search, $searchMeta -- Atlas Search full-text
$listSearchIndexes -- Atlas Search index management
$rankFusion, $score, $scoreFusion -- Atlas Search scoring
$listClusterCatalog, $listSampledQueries, $querySettings, $queryStats -- Atlas diagnostics
$shardedDataDistribution -- Sharded cluster diagnostics
8.2 Custom JavaScript Execution
| Feature | Status | Notes |
|---|
$function expression | Partial | Evaluates first argument; no server-side JS engine |
$accumulator | Partial | Falls back to $sum with input field; no server-side JS |
$where query operator | Y | Simple expression evaluation via js_eval module |
8.3 Cold-Tier Routing Strategy
When a query contains operators not pushable to the Parquet/DataFusion cold tier, the coordinator employs one of these strategies:
- Post-filter materialization: QE returns candidate rows; coordinator applies SE-level BSON filter
- SE routing: Query is routed entirely through the storage engine, which reads only hot data
- Federated merge: Hot results from SE + cold results from QE are merged; post-filter applied
Operators that trigger post-filter materialization on cold tier:
$nin, $regex (complex patterns), $all, $size, $mod
$elemMatch with range conditions on LIST columns
$type without schema information
- Bitwise operators (
$bitsAllSet, $bitsAllClear, $bitsAnySet, $bitsAnyClear)
Operators that trigger SE-only routing:
$geoWithin, $geoIntersects, $near, $nearSphere
$expr, $where, $jsonSchema
- Collation-aware queries
8.4 Fail-Closed Semantics (E4-S1)
Unknown or unrecognized query operators are handled with fail-closed semantics:
- SE filter evaluator returns
FilterOperator::Invalid (matches nothing)
- QE scan abandons SQL pushdown and returns all rows for post-filtering
- This ensures no silent data loss from unsupported operators
9. Summary Statistics
| Category | Total Tokens | SE (Hot) | QE (Cold) | Federated |
|---|
| Query Operators | 31 | 31 Y | 15 Y, 12 P, 4 N | 31 (RT for N) |
| Update Operators | 23 | 21 Y, 2 P | -- | -- |
| Projection Operators | 3 | 3 Y | -- | 3 RT |
| Aggregation Stages | 51 | 30 Y, 8 P | 10 Y/P | 51 (RT for N) |
| Aggregation Expressions | 182 | 178 Y, 4 P | ~60 Y/P | 182 (RT for N) |
| Accumulators | 25 | 24 Y, 1 P | 6 Y/P | 25 (RT for N) |
| Total | 308 (+7 ext.) | 287 Y, 14 P | | All handled |
All 308 reference MQL tokens are handled by at least one tier. Operators not natively supported on the cold tier are routed through the hot tier or handled via post-filter materialization in the federated path.