Skip to content

[finding][drivers] driver-mongodb cannot take a structured GroupByNode at all — the object stringifies into a "[object Object]" $group._id #6850

Description

@claude

Found while implementing #6401 (GroupByNode.alias on the SQL faces). Adjacent to it, not created by it. Filed unassigned, recording not claimingdriver-mongodb is inside the #5499 investment freeze.

The finding

GroupByNodeSchema declares a UNION: a bare field name, or a structured { field, dateGranularity?, alias? } node. driver-mongodb can only take the first half.

packages/drivers/driver-mongodb/src/mongodb-aggregation.ts:

groupBy?: string[];                       // :38 — half of the declared union
...
if (opts.groupBy && opts.groupBy.length > 0) {
  for (const field of opts.groupBy) {
    groupId[field] = `$${field}`;         // :66-69
  }
}
...
for (const field of opts.groupBy) {
  project[field] = `$_id.${field}`;       // :85-88 — mirrored in $project
}

A structured node is an object in that loop. groupId[field] stringifies it, so the $group._id key becomes the literal "[object Object]" and its value the literal "$[object Object]" — a field path that matches nothing. The $project stage mirrors the same key.

So the aggregation does not refuse and does not throw: it returns rows grouped by a nonexistent field path, under a column named [object Object].

Why tsc never saw it

packages/drivers/driver-mongodb/src/mongodb-driver.ts:512 passes the value through an any cast:

groupBy: (query as any).groupBy,

so the declared GroupByNode[] union never meets that string[] annotation. The annotation is a restatement of the protocol that drifted from it — the same shape #6212 closed for driver-turso's remote transport, which read groupBy as string[] and died on "[object Object]" as an unsafe identifier. That one at least failed loudly; this one answers.

Scope note — this is NOT the alias divergence

#6401 converged the three SQL faces onto alias ?? field for the projected column. driver-mongodb is not a fourth face of that divergence: the alias is unreachable here rather than ignored, because the whole structured half of the union is. Fixing alias alone would not help — the node has to be destructured first.

Recorded as a measured DEBT row in scripts/check-driver-conformance.mjs (the driver-mongodb × AGGREGATION_CASES cell) by #6401, so the conformance matrix carries the verdict rather than an omission.

Relationship to #6814

#6814 is the count_distinct disagreement for the same frozen pair — a wrong NUMBER from a lowering that exists. This is a different defect: a declared SHAPE that has no lowering at all. Same package, same freeze, separate cells; filing separately so the freeze is lifted against a measured list rather than one line item.

Verdict

Read from the source; not executed — this package has no server-free aggregation suite for the cell, which is part of the debt (the real-mongod suites are opt-in since #5517, so whatever closes this needs a server-free half like mongodb-filter-logic-translation.test.ts has).

Not fixed here: #5499 freezes the package, and #6401's ruling kept mechanical alignment out of the enforce change on principle — a frozen driver gets an honest row or a mechanical alignment, never a flip.

Related: #6401, #6814, #6212, #5499, ADR-0049.


Generated by Claude Code

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions