You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Unblocked now that #5431 merged (f7df82ca8) — this was held serially behind it because its call site (matchStage[fieldPath] = {$not: coerced[0]}) is the exact value-compilation point #5373 rewrote.
Worth recording, because the obvious guess is wrong: #5431 did not fix or shrink this. That call site now receives a real value instead of a stringified one, but {$not: 'x'} constraining nothing is an operator-layer defect and is independent of the comparand encoding. It still needs fixing exactly as this issue describes.
That makes this the third distinct layer on the same face, each ruled separately: #5345 refused operators with no mapping, #5373 fixed the comparand encoding, and this one is an operator that has a mapping pointing at the wrong target. Related but not a duplicate: #5433 is the same class on the generateSql exit rather than the mingo one, and is not bundled here.
同样是做 #5345 时逐个实测「这个面声明支持的 11 个算子各自编译成什么」发现的。不属于 #5345 的范围面(那一单裁的是没有 cube 映射的算子;
$notContains有映射,只是映射到了一个错的目标),按 Prime Directive #10 单独记在这里,unassigned。位置
packages/plugins/driver-memory/src/memory-analytics.ts的convertOperatorToMongo(约 :700):调用点(
query()Stage 1)把它填成matchStage[fieldPath] = { $not: coerced[0] }。现象(实测)
3 行数据,
name分别为alpha/beta/gamma(其中只有beta含et):wherefind()行数{ name: { $notContains: 'et' } }编译出来的
$match是{ name: { $not: 'et' } }。mingo 的$not期望的是一个正则或算子表达式,不是裸标量;给一个裸字符串时它不构成约束,于是整条谓词等于没写 —— 全表通过。对照:
contains映射到$regex是对的({ name: { $regex: 'et' } }取到 1 行,与find()一致)。正确的取反形式应当是{ name: { $not: /et/ } }或{ name: { $not: { $regex: 'et' } } },而不是把比较数直接塞进$not。为什么是 bug
$or/$not整条丢,$between/$startsWith/$null/$regex因无 cube 映射而丢 —— 聚合结果被放大 #5345 完全同一类后果,只是机制不同:driver-memory 的 analytics 面静默丢弃大半个 filter:$or/$not整条丢,$between/$startsWith/$null/$regex因无 cube 映射而丢 —— 聚合结果被放大 #5345 是谓词没被生成,这里是谓词被生成了但不起作用。对作者而言两者不可区分 —— 都是一个看起来正常的图表统计了它本该排除的行。$or/$not整条丢,$between/$startsWith/$null/$regex因无 cube 映射而丢 —— 聚合结果被放大 #5345 修不到它,而且 driver-memory 的 analytics 面静默丢弃大半个 filter:$or/$not整条丢,$between/$startsWith/$null/$regex因无 cube 映射而丢 —— 聚合结果被放大 #5345 之后它更需要修。 driver-memory 的 analytics 面静默丢弃大半个 filter:$or/$not整条丢,$between/$startsWith/$null/$regex因无 cube 映射而丢 —— 聚合结果被放大 #5345 让本面的算子词表从MONGO_TO_CUBE_OPERATOR派生,$notContains在表里,所以它被声明为本面支持并且会通过ANALYTICS_FILTER_CAPABILITIES的门。声明支持而编译成空操作,正是 Prime Directive chore: version packages #10 的 declared ≠ enforced。generateSql那一半是对的。operatorToSql给notContains的是NOT LIKE,所以 SQL 回显显示了一个真实的排除谓词,而实际执行的 in-memory 管线没有排除任何行 —— 回显与执行不一致,和/analytics/sql回显的 SQL 丢掉$startsWith/$endsWith谓词:回显比实际执行的查询更宽,无法复现结果 #5333 是同一类「回显比实际更可信/更不可信」的问题,只是方向相反。建议(不代裁决)
convertOperatorToMongo保持返回$not,由调用点把比较数包成{ $not: { $regex: value } };或者干脆让映射返回一个结构而不是一个算子名(contains/notContains是这张表里唯二需要包装比较数的项,现在被硬塞进了「算子名 → 算子名」的形状里)。'inDateRange': '$gte'(注释自称 "Will need special handling",但没有任何调用点做那个 special handling)与opMap[operator] || '$eq'的兜底 —— 一个拼错的 cube 算子名会静默变成相等比较。我没有实测这两条,只是读到时觉得可疑,一并记下不代表判断。未验证的部分
只在 in-memory(mingo)路径上实测。没有确认 mingo 对
{$not: 'et'}是「忽略」还是「按某种语义匹配全部」—— 观察到的结果是 3 行(全表),但我没有读 mingo 源码确认它内部走的是哪一条。结论(全表通过)是实测的,机制描述是推断的。严重度请 PM 按 triage 定。关联:#5345(同文件、同一轮核对里发现;它裁的是无映射的算子)、#5373(同一轮里发现的比较数往返缺陷)、#3948(no-silent-drop)、#5333(analytics SQL 回显与执行不一致)。