Skip to content

Commit 7d5db61

Browse files
committed
REP-6465: Make dockey always include shard key fields even if empty.
This amends PR #127 so that, if a document lacks a shard key field, the generated document key will include that field with a null value. This matches the server’s internal logic and seems safer besides.
1 parent f398a89 commit 7d5db61

File tree

3 files changed

+15
-72
lines changed

3 files changed

+15
-72
lines changed

dockey/agg.go

Lines changed: 7 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@
44
package dockey
55

66
import (
7-
"maps"
8-
"slices"
9-
"strconv"
10-
7+
"github.com/10gen/migration-verifier/mslices"
118
"github.com/samber/lo"
129
"go.mongodb.org/mongo-driver/bson"
1310
)
@@ -21,69 +18,12 @@ import (
2118
func ExtractTrueDocKeyAgg(fieldNames []string, docExpr string) bson.D {
2219
assertFieldNameUniqueness(fieldNames)
2320

24-
var docKeyNumKeys bson.D
25-
numToKeyLookup := map[string]string{}
26-
27-
for n, name := range fieldNames {
28-
var valExpr = docExpr + "." + name
29-
30-
// Aggregation forbids direct creation of an object with dotted keys.
31-
// So here we create an object with numeric keys, then below we’ll
32-
// map the numeric keys back to the real ones.
33-
34-
nStr := strconv.Itoa(n)
35-
docKeyNumKeys = append(docKeyNumKeys, bson.E{nStr, valExpr})
36-
numToKeyLookup[nStr] = name
37-
}
38-
39-
// Now convert the numeric keys back to the real ones.
40-
return mapObjectKeysAgg(docKeyNumKeys, numToKeyLookup)
41-
}
42-
43-
// Potentially reusable:
44-
func mapObjectKeysAgg(expr any, mapping map[string]string) bson.D {
45-
// We would ideally pass mapping into the aggregation and $getField
46-
// to get the mapped key, but pre-v8 server versions required $getField’s
47-
// field parameter to be a constant. (And pre-v5 didn’t have $getField
48-
// at all.) So we use a $switch instead.
49-
mapAgg := bson.D{
50-
{"$switch", bson.D{
51-
{"branches", lo.Map(
52-
slices.Collect(maps.Keys(mapping)),
53-
func(key string, _ int) bson.D {
54-
return bson.D{
55-
{"case", bson.D{
56-
{"$eq", bson.A{
57-
key,
58-
"$$numericKey",
59-
}},
60-
}},
61-
{"then", mapping[key]},
62-
}
63-
},
64-
)},
65-
}},
66-
}
67-
6821
return bson.D{
69-
{"$arrayToObject", bson.D{
70-
{"$map", bson.D{
71-
{"input", bson.D{
72-
{"$objectToArray", expr},
73-
}},
74-
{"in", bson.D{
75-
{"$let", bson.D{
76-
{"vars", bson.D{
77-
{"numericKey", "$$this.k"},
78-
{"value", "$$this.v"},
79-
}},
80-
{"in", bson.D{
81-
{"k", mapAgg},
82-
{"v", "$$value"},
83-
}},
84-
}},
85-
}},
86-
}},
87-
}},
22+
{"$arrayToObject", mslices.Of(lo.Map(
23+
fieldNames,
24+
func(fieldName string, _ int) [2]string {
25+
return [...]string{fieldName, docExpr + "." + fieldName}
26+
},
27+
))},
8828
}
8929
}

dockey/raw.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ func ExtractTrueDocKeyFromDoc(
2323

2424
var dk bson.D
2525
for _, field := range fieldNames {
26+
var val bson.RawValue
2627

2728
// This is how sharding routes documents: it always
2829
// splits on the dot and looks deeply into the document.
@@ -31,13 +32,13 @@ func ExtractTrueDocKeyFromDoc(
3132

3233
if errors.Is(err, bsoncore.ErrElementNotFound) || errors.As(err, &bsoncore.InvalidDepthTraversalError{}) {
3334
// If the document lacks a value for this field
34-
// then don’t add it to the document key.
35-
continue
36-
} else if err == nil {
37-
dk = append(dk, bson.E{field, val})
38-
} else {
35+
// then make it null in the document key.
36+
val = bson.RawValue{Type: bson.TypeNull}
37+
} else if err != nil {
3938
return nil, errors.Wrapf(err, "extracting doc key field %#q from doc %+v", field, doc)
4039
}
40+
41+
dk = append(dk, bson.E{field, val})
4142
}
4243

4344
docKey, err := bson.Marshal(dk)

dockey/test/cases.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ var TestCases = []TestCase{
5252
},
5353
DocKey: bson.D{
5454
{"_id", "ccc"},
55+
{"foo.bar.baz", nil},
5556
},
5657
},
5758
{
@@ -73,6 +74,7 @@ var TestCases = []TestCase{
7374
},
7475
DocKey: bson.D{
7576
{"_id", "eee"},
77+
{"foo.bar.baz", nil},
7678
},
7779
},
7880
}

0 commit comments

Comments
 (0)