Conversation
The mongo hook records each Collection method as a function call with its
actual arguments. That is fine for reading one AppMap, but it keeps Mongo
operations out of everything that works on sql_query events: the digest,
the query diff in change reports, and the Database lifeline in sequence
diagrams.
Each recorded operation now also gets a sql_query event, nested under the
function call the way the Prisma hook nests the SQL it observes. The event
has database_type "mongodb" and a statement in shell form with a normalized
argument shape:
db.users.updateOne({"_id": ?}, {"$set": {"name": ?}}, {"upsert": ?})
Keys and operators are kept in order, every leaf value becomes `?`, arrays
collapse to their distinct element shapes (so an insertMany of a thousand
documents of one shape is one statement, and `$in` lists do not vary by
length), and aggregation and update pipelines keep every stage in order.
Name arguments (a distinct field, an index name, a new collection name)
stay verbatim. BSON values, class instances, Buffers, functions and cyclic
or very deep structures are leaves. The rules are written down at the top
of src/hooks/mongoQuery.ts; the Java agent implements the same rules.
The query return event is emitted when the driver hands back its promise
and is fixed up with the real elapsed time, or turned into an exception
event, when the promise settles. Cursors (find, aggregate, listIndexes,
watch) are not promises, so their return stays as emitted. Methods the
driver implements on top of other Collection methods (findOne calls find)
produce one query event, for the outer call only.
The fixture now also covers insertMany, find with an operator and options,
aggregate, createIndex, a caught duplicate key error, and deleteMany.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LntddoBsqjRDRBepBx7oLZ
|
I'm not convinced recording mongo db queries as |
|
It will cause a lot of problems downstream to put anything but SQL in that
field.
I’m not sure what to recommend.
…On Thu, Sep 17, 2026 at 09:44 Rafał Rzepecki ***@***.***> wrote:
*dividedmind* left a comment (getappmap/appmap-node#239)
<#239 (comment)>
I'm not convinced recording mongo db queries as sql_query is the right
shape – the documentation, all of our tooling and even the field name makes
it clear that SQL is what is expected there. It feels like a hack – I get
that it allows leveraging some things that care about sql_query, but most
of precisely these things expect SQL there and need to be patched for this
to work reliably anyway. Since many of them need to be patched anyway,
perhaps it'd be more robust and cleaner to introduce a different
well-defined structure for non-SQL database queries like this. @kgilpin
<https://github.com/kgilpin> wdyt?
—
Reply to this email directly, view it on GitHub
<#239?email_source=notifications&email_token=AAAVC665DULOIBSY4ZEFZM35PPTDTA5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTKNZRGUZTQMRSHAY2M4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJLDGN5XXIZLSL5RWY2LDNM#issuecomment-5715382281>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAAVC66SAPO3SUJGLO7JOC35PPTDTAVCNFSNUABFKJSXA33TNF2G64TZHM3DSMBRGI3DOOBZHNEXG43VMU5TKNBYG43TMNRSHEZKC5QC>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Yes that's exactly my concern. My take is if we really want to have normalized mongo queries somewhere we need to invent a specific, different, place and form to put them in the schema. I'm not sure if it's really worth it, though being able to eg. see the changed queries in the query reports might be a good reason – currently mongo tracing is kind of a special case in appmap-node, and the way it's recorded is mostly to make it clear and readable in the diagrams (no normalization of any kind iirc), so it might be worthwhile to systematize it (maybe normalize it too) so other agents (eg. java) can generate the same shape, then downstream tool support could be enhanced with support for this as needed. But this is something we'd need to discuss, plan and design first. |
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved issues remain in bulk-write pipeline normalization and large string-array handling, with callback coverage also missing.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Adds normalized MongoDB sql_query events alongside existing collection call events for query-oriented AppMap analyses.
Changes:
- Normalizes MongoDB operation arguments and query statements.
- Records query lifecycle and failure events.
- Expands unit and integration coverage with updated snapshots.
File summaries
| File | Reviewed change |
|---|---|
test/mongo/index.js |
Expanded MongoDB integration scenarios. |
test/__snapshots__/mongo.test.ts.snap |
Updated expected AppMap output. |
src/hooks/mongoQuery.ts |
Formats and normalizes MongoDB statements. |
src/hooks/mongo.ts |
Instruments MongoDB query events. |
src/hooks/__tests__/mongoQuery.test.ts |
Tests normalization behavior. |
Review details
- Files reviewed: 5/5 changed files
- Comments generated: 3
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| if (Array.isArray(value) && value.every((v) => typeof v === "string")) | ||
| return `[${value.map((v) => JSON.stringify(v)).join(", ")}]`; |
| return shape(value, true); | ||
| case "document": | ||
| // An update can be a pipeline (an array of stages) instead of a document. | ||
| return shape(value, name === "update" && Array.isArray(value)); |
| const queryEvents = queryCallEvents(recordings, statement); | ||
|
|
||
| const startTime = getTime(); | ||
| args.push((err: unknown, res: unknown) => { | ||
| setCustomInspect(res, customInspect); |
|
Agreed, on both points. We will step back and design this properly instead: a dedicated place in the schema for non-SQL database queries, one normalized shape that both agents produce, and downstream support added deliberately. The normalization rules and the Java port in these PRs are meant to feed into that design rather than merge as they are. This PR and getappmap/appmap-java#330 go back to draft as reference for the redesign. getappmap/appmap-js#2401 is closed, since it only existed to support this approach. Generated by Claude Code |
|
Another idea might be to add a generic marker and field for normalized data. This way the events from mongodb as recorded by appmap-node today could be augmented with something like |
The mongo hook records each
Collectionmethod as a function call with its actual arguments, under a syntheticmongodb/<collection>class. That is readable in a single AppMap, but it keeps Mongo operations out of everything that works onsql_queryevents: the digest, the query section of change reports, and the Database lifeline in sequence diagrams.What changes
sql_queryevent, nested under the function call the way the Prisma hook nests the SQL it observes. It hasdatabase_type: "mongodb"and a statement in shell form with a normalized argument shape, for exampledb.users.updateOne({"_id": ?}, {"$set": {"name": ?}}, {"upsert": ?}).The shape rules (written down at the top of
src/hooks/mongoQuery.ts)?.{"$in": [1, 2, 3]}is{"$in": [?]}, and aninsertManyof a thousand documents of one shape is one statement.distinctfield, an index name, a new collection name) stay verbatim.options.db.getCollection("my-coll").?or are skipped. Formatting never throws; a hostile argument renders asdb.coll.find(?).Edge cases handled
find,aggregate,listIndexes,watch) are not promises. Their statement is recorded when the cursor is created, so.sort(),.limit()and friends applied afterwards are not part of it.findOnecallsfind). The inner call keeps its function call event, but only the outermost operation gets a query event, so one logical operation is one query.undefinedarguments are omitted, sofind()andfind(undefined)are the same statement.Companion changes
normalizeSQLhas to leavedatabase_type: "mongodb"alone. Without that change the fallback obfuscation treats quoted keys as string literals and a pair of$operatorsas a dollar-quoted string, and the digest showsdb.users.updateOne({?: ?}, {?instead of the statement.Test
src/hooks/__tests__/mongoQuery.test.ts: 25 unit tests for the shape rules. The Java agent's unit tests assert the same strings.test/mongo: the fixture now also runsinsertMany, afindwith an operator and options, anaggregate,createIndex, a caught duplicate key error, anddeleteMany. The snapshot was regenerated against MongoDB 8.0.4. The test still requiresMONGODB_URI, as before, and CI provides it.yarn lint,yarn typecheck, and the unit suite pass.Written by Claude in a Claude Code session for Elizabeth Lawler. The commit carries Claude as author.
🤖 Generated with Claude Code
https://claude.ai/code/session_01LntddoBsqjRDRBepBx7oLZ