Node driver mutates input, even when cloned

Encountered a strange bug in the NodeJs driver. Node mutates not only the input of insertMany, but also the source of the input. I have tried four different ways to clone an array. All four should in theory create a copy of the array, so the original source is left untouched. However in three of four methods the mongo driver still mutates the original array (although the original array is never passed to the mongo client).

// this array is cloned, then inserted. It is expected that this array is not changed
const events = [{ a: "foo", b: "bar" }]; 
assert.deepStrictEqual(events, [{ a: "foo", b: "bar" }]);

const cloneA = [...events];
await collection.insertMany(cloneA); 
assert.deepStrictEqual(events, [{ a: "foo", b: "bar" }]); // this assertions error, but should not


const cloneB = Array.from(events);
await collection.insertMany(cloneB);
assert.deepStrictEqual(events, [{ a: "foo", b: "bar" }]); // this assertions error, but should not

const cloneC = events.map((a) => a);
await collection.insertMany(cloneC);
assert.deepStrictEqual(events, [{ a: "foo", b: "bar" }]); // this assertions error, but should not

const cloneD = JSON.parse(JSON.stringify(events)); // works
await collection.insertMany(cloneD);
assert.deepStrictEqual(events, [{ a: "foo", b: "bar" }]); // this assertions works, so this is an inefficient way to ensure immutability of events

I do not think it is a bug. I think this is how it should work. In your first three cases, you are creating a new list that contains the same objects as the source, namely events. You are not copying the objects. And insertMany has (somewhat) nothing to do with the behaviour you see.

const events = [ { a: "foo", b: "bar" } ] ;
const cloneA = [ ...events ] ;

// The following mutate the first object of cloneA
cloneA[0].b = "BAR" ;

// But it also mutate the first object of events because they are the same objects
cloneA[0] === events[0] ; 

// You could push a new object into cloneA but it won't change events
cloneA.push( { b : 1 } ) ;

If you modify your cloneC case with

cloneC = events.map( (item) => Object.assign({},item) ) ;

to add copies of item into cloneC.

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.