What?
Trying to remove an element from an array of objects in a mongo document.
I use: go version go1.17.1 darwin/amd64; go.mongodb.org/mongo-driver v 1.8.4; MongoDB 5.0.6 Enterprise
Shortened version of the function with everything as plain as possible:
func (r *Repo) UpdateModelByID(ctx context.Context, id string) error {
objID, err := primitive.ObjectIDFromHex(id)
// I actually handle err here, it's nil
filter := bson.D{{"_id", objID}}
update = bson.D{{
Key: "$pull",
Value: bson.E{
Key: "data",
Value: bson.E{
Key: "field_type",
Value: bson.E{
Key: "$in",
Value: []string{"field_type_1", "field_type_2"},
},
},
},
}}
log.Debugln("UPDATE", update)
result, err = cdm.getTemplatesCollection().UpdateOne(ctx, filter, update)
// I actually handle err here, it's nil
log.Debugf("RESULT_OF_UPDATE: % v", result)
}
Expected:
Document with id I provided will no longer have elements in array "data" that have a field "field_type" equal to "field_type_1" or "field_type_2"
Got:
DEBU[0023] UPDATE [{$pull {data {field_type {$in [field_type_1, field_type_2]}}}}]
DEBU[0023] RESULT_OF_UPDATE: &{MatchedCount:1 ModifiedCount:0 UpsertedCount:0 UpsertedID:<nil>}
Same command through mongosh:
db.templates.updateOne(
{ _id: ObjectId("6228a89d621d19a2f7977d2f") },
{ $pull: { data: {field_type: {$in: ["field_type_1", "field_type_2"]}}}
}
)
{ acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 1,
upsertedCount: 0 }
And the elem-s are gone from the array.
Why could this be?
I did notice that native query has single curly brackets (just an object), while Go code uses bson.D which technically is an array of those same objects (bson.E) -> [{}].
I tried changing mongosh command to test:
db.templates.updateOne(
{ _id: ObjectId("6228a89d621d19a2f7977d2f") },
[{ $pull: { data: {field_type: {$in: ["field_type_1", "field_type_2"]}}}
}]
)
MongoServerError: Unrecognized pipeline stage name: '$pull'
In Go I tried using bson.E instead of bson.D (though the latter is recommended for commands per documentation) and got this:
DEBU[0030] UPDATE {$pull {data {field_type {$in [field_type_1, field_type_2]}}}}
ERRO[0030] cannot update model by id: update document must contain key beginning with '$' method=UpdateModelByID templateId=6228a89d621d19a2f7977d2f
CodePudding user response:
bson.D
models a document, with an ordered list of key-value pairs, where the key is the property name, value is the property's value.
So if you intend to use bson.D
to model documents, you always have to write a bson.D
composite literal where there's a document in the equivalent shell command.
So your update
document must look like this:
update := bson.D{{
Key: "$pull", Value: bson.D{{
Key: "data", Value: bson.D{{
Key: "field_type", Value: bson.D{{
Key: "$in", Value: []string{"field_type_1", "field_type_2"},
}}},
}},
}},
}
If you omit the named fields from the composite literals, it's reduced to this:
update := bson.D{
{"$pull", bson.D{{
"data", bson.D{{
"field_type", bson.D{{
"$in", []string{"field_type_1", "field_type_2"},
}}},
}},
}},
}
Yes, it's kinda ugly. Please note that if order of elements does not matter, it's much easier to use bson.M
values to define documents (it's a map). For details, see bson.D vs bson.M for find queries
Your update
could look like this defined with bson.M
:
update := bson.M{
"$pull": bson.M{
"data": bson.M{
"field_type": bson.M{
"$in": []string{"field_type_1", "field_type_2"},
},
},
},
}