CSHARP-5942: Fix serializer resolution for dictionary paths with numeric string keys#1923
CSHARP-5942: Fix serializer resolution for dictionary paths with numeric string keys#1923damieng wants to merge 6 commits intomongodb:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Fixes a regression in string-based field path serializer resolution where all-digit path segments (e.g., "Buckets.10") were incorrectly treated as array indexes when navigating through dictionaries with DictionaryRepresentation.Document, leading to update operators like $addToSet failing due to the wrong serializer being selected.
Changes:
- Updates
StringFieldDefinitionHelper.Resolveto handle"$"and all-digit segments separately, attempting document-member resolution for numeric segments before falling back to array-item resolution. - Adds regression tests covering
AddToSet/AddToSetEachwith string and expression paths through dictionaries (including numeric string keys and different dictionary/value shapes).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
src/MongoDB.Driver/FieldDefinition.cs |
Adjusts serializer resolution logic for numeric path segments to prefer document-member resolution (fixing numeric dictionary key paths). |
tests/MongoDB.Driver.Tests/UpdateDefinitionBuilderTests.cs |
Adds regression tests to ensure update rendering works for dictionary paths (including numeric string keys). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
I think we have to double-check the changes done to
It seems like we might want to double-check if the Key has int-based representation, and return |
sanych-sun
left a comment
There was a problem hiding this comment.
LGTM, but please double-check the comment in tests, it seems to be misleading.
| [Fact] | ||
| public void AddToSet_with_string_path_through_array_rep_dictionary() | ||
| { | ||
| // When dictionary uses ArrayOfDocuments representation, string path resolution |
There was a problem hiding this comment.
I think the comment is wrong, the issue was about the case when dictionary represented as Document. Checks in DictionarySerializerBase.TryGetItemSerializationInfo suggests there are no problem with ArrayOfDocuments representation too.
Summary
DictionarySerializerBase<TDictionary, TKey, TValue>.TryGetItemSerializationInfo()to returnfalsefor Document-represented dictionaries with non-numeric key typesAddToSetwith dictionary-based nested collection paths, including numeric string keysBackground
A regression was introduced in 3.7.0 via CSHARP-5572 (#1700) that changed
DictionarySerializerBase<TDictionary, TKey, TValue>.TryGetItemSerializationInfo()to always returntrue, even forDictionaryRepresentation.Document. Previously it returnedfalsefor Document representation.This broke string-based field path resolution for dictionaries with all-digit keys (e.g.,
"Buckets.10"), becauseStringFieldDefinitionHelper.Resolvetreats all-digit path segments as array indices and callsIBsonArraySerializer.TryGetItemSerializationInfo(). When the dictionary serializer now returnstrue, the resolver picks up aKeyValuePairSerializerinstead of the dictionary's value serializer. Operations likeAddToSet,Push, andPullthen fail becauseKeyValuePairSerializerdoes not implementIBsonArraySerializer.Root cause
In CSHARP-5572,
DictionarySerializerBase.TryGetItemSerializationInfo()was simplified to unconditionally returntrue. The original code returnedfalseforDictionaryRepresentation.Document, which causedStringFieldDefinitionHelper.Resolveto correctly fall through the array-index branch and setresolvedFieldSerializer = null, lettingAddToSetresolve the item serializer from the registry.Fix
Restore the guard in
TryGetItemSerializationInfo()for Document-represented dictionaries, but with a refinement: allowtruewhenTKeyis a numeric type (int, long, short, byte, etc.), since dictionaries with integer keys serialized as Document look like BSON arrays with numeric indices. For string-keyed dictionaries — the common case — the method returnsfalsefor Document representation, matching the pre-3.7.0 behavior.