I need to change a value of a field in a mongoDB document recursively.
More or less, this is just a find and replace for a value of a field if the field name and the (old) value matches.
Example Document:
<code>{
"topLevel": {
"level1": [
{
"itemKey": "N-99999",
"level2": [
{
"itemKey": "N-99999",
"level3": [
{
"itemKey": "N-99999"
},
{
"itemKey": "a-4157-637"
},
{
"itemKey": "t-3213-569"
},
{
"itemKey": "s-3984-763"
},
{
"itemKey": "n-5996-963"
}
]
}
]
}
]
}
}
</code>
<code>{
"topLevel": {
"level1": [
{
"itemKey": "N-99999",
"level2": [
{
"itemKey": "N-99999",
"level3": [
{
"itemKey": "N-99999"
},
{
"itemKey": "a-4157-637"
},
{
"itemKey": "t-3213-569"
},
{
"itemKey": "s-3984-763"
},
{
"itemKey": "n-5996-963"
}
]
}
]
}
]
}
}
</code>
{
"topLevel": {
"level1": [
{
"itemKey": "N-99999",
"level2": [
{
"itemKey": "N-99999",
"level3": [
{
"itemKey": "N-99999"
},
{
"itemKey": "a-4157-637"
},
{
"itemKey": "t-3213-569"
},
{
"itemKey": "s-3984-763"
},
{
"itemKey": "n-5996-963"
}
]
}
]
}
]
}
}
What I tried, but doesn’t work:
<code>func replaceItemKey(ctx context.Context, coll *mongo.Collection, old, new string) (*mongo.UpdateResult, error) {
filter := bson.D{
{Key: "toplevel.level1.itemKey", Value: old},
{Key: "toplevel.level1.level2.itemKey", Value: old},
{Key: "toplevel.level1.level2.level3.itemKey", Value: old},
}
update := bson.D{
{Key: "$set", Value: bson.D{{Key: "toplevel.$[l1]level1.itemKey", Value: new}}},
{Key: "$set", Value: bson.D{{Key: "toplevel.level1.$[].level2.$[l2].itemKey", Value: new}}},
{Key: "$set", Value: bson.D{{Key: "toplevel.level1.$[].level2.$[].level3.$[l3].itemKey", Value: new}}},
}
opts := options.Update().SetArrayFilters(
options.ArrayFilters{
Filters: []interface{}{
bson.D{{Key: "l1.itemKey", Value: bson.D{{Key: "$eq", Value: old}}}},
bson.D{{Key: "l2.itemKey", Value: bson.D{{Key: "$eq", Value: old}}}},
bson.D{{Key: "l3.itemKey", Value: bson.D{{Key: "$eq", Value: old}}}},
},
},
)
return coll.UpdateMany(ctx, filter, update, opts)
}
</code>
<code>func replaceItemKey(ctx context.Context, coll *mongo.Collection, old, new string) (*mongo.UpdateResult, error) {
filter := bson.D{
{Key: "toplevel.level1.itemKey", Value: old},
{Key: "toplevel.level1.level2.itemKey", Value: old},
{Key: "toplevel.level1.level2.level3.itemKey", Value: old},
}
update := bson.D{
{Key: "$set", Value: bson.D{{Key: "toplevel.$[l1]level1.itemKey", Value: new}}},
{Key: "$set", Value: bson.D{{Key: "toplevel.level1.$[].level2.$[l2].itemKey", Value: new}}},
{Key: "$set", Value: bson.D{{Key: "toplevel.level1.$[].level2.$[].level3.$[l3].itemKey", Value: new}}},
}
opts := options.Update().SetArrayFilters(
options.ArrayFilters{
Filters: []interface{}{
bson.D{{Key: "l1.itemKey", Value: bson.D{{Key: "$eq", Value: old}}}},
bson.D{{Key: "l2.itemKey", Value: bson.D{{Key: "$eq", Value: old}}}},
bson.D{{Key: "l3.itemKey", Value: bson.D{{Key: "$eq", Value: old}}}},
},
},
)
return coll.UpdateMany(ctx, filter, update, opts)
}
</code>
func replaceItemKey(ctx context.Context, coll *mongo.Collection, old, new string) (*mongo.UpdateResult, error) {
filter := bson.D{
{Key: "toplevel.level1.itemKey", Value: old},
{Key: "toplevel.level1.level2.itemKey", Value: old},
{Key: "toplevel.level1.level2.level3.itemKey", Value: old},
}
update := bson.D{
{Key: "$set", Value: bson.D{{Key: "toplevel.$[l1]level1.itemKey", Value: new}}},
{Key: "$set", Value: bson.D{{Key: "toplevel.level1.$[].level2.$[l2].itemKey", Value: new}}},
{Key: "$set", Value: bson.D{{Key: "toplevel.level1.$[].level2.$[].level3.$[l3].itemKey", Value: new}}},
}
opts := options.Update().SetArrayFilters(
options.ArrayFilters{
Filters: []interface{}{
bson.D{{Key: "l1.itemKey", Value: bson.D{{Key: "$eq", Value: old}}}},
bson.D{{Key: "l2.itemKey", Value: bson.D{{Key: "$eq", Value: old}}}},
bson.D{{Key: "l3.itemKey", Value: bson.D{{Key: "$eq", Value: old}}}},
},
},
)
return coll.UpdateMany(ctx, filter, update, opts)
}
I know this is not recursively at all. It just tries to change the value in 3 levels.
Recursively would be better.
I’d prefer to change the value in one statement.
Doing it in a statement per level works fine. But I’m not aware on the performance impact if I have to change thousends of documents.
Thanks a lot.