-
Type: Bug
-
Resolution: Done
-
Priority: Critical - P2
-
None
-
Affects Version/s: 4.1.1, 5.6.0
-
Component/s: Aggregation
What problem are you facing?
There's a bug in the AggregationCursor that causes the `transform` function passed to `AggregationCursor.map()` to be called multiple times consecutively for the same document, when using `hasNext()` in combination with `next()`, which is a very common pattern in working with aggregation cursors.
When this map function transforms the type of the to-be-returned document (let's say from type A to type B) (note: that's what most people use `map` for), then calling `hasNext()` and then `next()` causes a TypeError to occur. From what I understand, it is because `hasNext()` saves the map function as a transform property on the aggregation cursor, which it then detects while executing `next()` to be an "old transform" which it applies first before it applies the map function. Obviously, `transform(transform(A))` is invalid when `transform` is a function `(arg: A) => B`
See below for a simple reproducible example.
I'm marking this as a critical issue because unless `transform` is a function (arg: A | B) => B`, this bug causes the entire NodeJS program to crash. Also, both the `if (cursor.hasNext()) doSomething(cursor.next());` pattern as well as having the map function transform the type of its input, are very common patterns.
There is, however, a workaround: simply don't use `hasNext()` and just call `next()` until it returns `null`. But that means `hasNext()` is simply unusable.
What driver and relevant dependency versions are you using?
MongoDB Node driver: 5.6.0, though I originally found it on 4.1.1 and probably affects all versions in between and probably some versions prior as well. That's for you to test
Steps to reproduce?
To reproduce, I'll use an edited version of the MongoDB usage example:
- Create a folder
- `yarn init`
- `yarn add mongodb` This installed v5.6.0 at the time of writing.
- Add the code in the first code block below into `index.js`
- Ensure you have a collection `deb.Customer` on a locally running Mongo instance with a bunch of documents in it, or edit the `uri`, `dbname` and `collname` variables in the code snippet.
- `node index.js`
- Observe that the output is what is displayed in the second code block
const { MongoClient } = require("mongodb"); // Replace the uri, dbname and collname with a connection string, db name and collection name that contain some documents for you const uri = "mongodb://localhost"; const dbname = "deb"; const collname = "Customer"; const client = new MongoClient(uri); async function run() { try { const database = client.db(dbname); const collection = database.collection(collname); // Do an aggregation (doesn't matter what it is), then perform a map that transforms the type. const cursor = collection.aggregate([ { $match: { _id: { $exists: true } } }, ]).map(doc => { const { _id, ...rest } = doc; console.log('map', _id); return { ...rest, id: doc._id.toHexString() }; }); let retrieved = 0; const limit = 10; while ((await cursor.hasNext()) && retrieved < limit) { console.log((await cursor.next())); retrieved++; } } finally { // Ensures that the client will close when you finish/error await client.close(); } } run().catch(console.dir);
map new ObjectId("59f86a80edaf5f0001b850bf") map undefined TypeError: Cannot read properties of undefined (reading 'toHexString') at AggregationCursor.<anonymous> (/mongo-cursor-map-problem/index.js:21:37) at nextDocument (/mongo-cursor-map-problem/node_modules/mongodb/lib/cursor/abstract_cursor.js:490:34) at next (/mongo-cursor-map-problem/node_modules/mongodb/lib/cursor/abstract_cursor.js:511:29) at node:internal/util:364:7 at new Promise (<anonymous>) at next (node:internal/util:350:12) at AggregationCursor.next (/mongo-cursor-map-problem/node_modules/mongodb/lib/cursor/abstract_cursor.js:223:16) at run (/mongo-cursor-map-problem/index.js:27:33) at processTicksAndRejections (node:internal/process/task_queues:96:5)
P.S. this issue reporting system is a horrible user experience, please consider switching to GitHub Issues or Linear or anything else less horrible than Jira.
- related to
-
NODE-5374 Cursor.hasNext should not transform documents
- Closed