Full repro:
(function() { const c = db.coll; c.drop(); c.insert({'a': [{}]}); assert.commandWorked(c.createIndex({'a.0.c': 1})); // First 0 is array index. // Second 0 is a field name. c.update({}, {$set: {'a.0.0.b': 'hi'}}); const res = assert.commandWorked(c.validate(true)); assert(res.valid, tojson(res)); })();
Step 1: Insert a document such as:
{'a': [{}]}
Step 2: Create an index, such as:
{'a.0.c': 1}
The key for the document we inserted above is null.
Now do an update:
c.update({}, {$set: {'a.0.0.b': 'hi'}});
The update driver determines that this change will not affect any indexes, so the index keys don't get recomputed.
But when we run validate(), they do get recomputed, and as part of that, validation fails
because we have a numerical field name in an object nested inside an array:
https://github.com/mongodb/mongo/blob/a8fe1d82c3c5484c7e8a6402a34bc45ea11d06f1/src/mongo/db/index/btree_key_generator.cpp#L261-L268
One way to fix this is to just add a special check to the update code.