I am trying to check if a value exist on the mongo db before appending new one to it but I keep getting an error every time.
obId, _ := primitive.ObjectIDFromHex(id)
query := bson.D{{Key: "_id", Value: obId}}
var result bson.M
er := r.collection.FindOne(ctx, bson.M{"_id": obId, "statusData.status": bson.M{"$in": []string{string(p.Status)}}}).Decode(&result)
if er != nil {
if er == mongo.ErrNoDocuments {
return nil, errors.New(fmt.Sprintf("ERR NA %v, %v", er.Error(), p.Status))
}
return nil, errors.New(fmt.Sprintf("ERR NORR %v", er.Error()))
}
doc, err := utils.ToDoc(p)
if err != nil {
return nil, errors.New(err.Error())
}
update := bson.D{{Key: "$set", Value: doc}}
res := r.collection.FindOneAndUpdate(ctx, query, update, options.FindOneAndUpdate().SetReturnDocument(1))
my document looks like this
{
"statusData": [
{
"status": "new",
"message": "You created a new dispatch request",
"createdAt": "1657337212751",
"updatedAt": null
},
{
"status": "assigned",
"message": "Justin has been assigned to you",
"createdAt": "1657412029130",
"updatedAt": null,
"_id": "62ca19bdf7d864001cabfa4a"
}
],
"createdAt": "2022-07-10T00:09:01.785Z",
.... }
there are different statuses and I want to be sure same status are not being sent to the db multiple times before updating the db with new value.
type StatusType string
const (
NEW StatusType = "new"
ACKNOWLEDGED StatusType = "acknowledged"
ASSIGNED StatusType = "assigned"
REJECT StatusType = "rejected"
CANCEL StatusType = "cancelled"
COMPLETE StatusType = "completed"
)
utils.ToDoc
func ToDoc(v interface{}) (doc *bson.D, err error) {
data, err := bson.Marshal(v)
if err != nil {
return
}
err = bson.Unmarshal(data, &doc)
return
}
Tried update
filter := bson.M{
"_id": obId,
"statusData.status": bson.M{"$ne": p.Status},
}
update := bson.M{
"$push": bson.M{
"statusData": newStatusToAdd,
},
"$set": bson.D{{Key: "$set", Value: doc}},
}
result, err := r.collection.UpdateOne(ctx, filter, update)
if err != nil {
// Handle error
return nil, errors.New(err.Error())
}
if result.MatchedCount == 0 {
// The status already exists in statusData
} else if result.ModifiedCount == 1 {
// new status was added successfuly
}
returns error
"write exception: write errors: [The dollar ($) prefixed field '$set' in '$set' is not allowed in the context of an update's replacement document. Consider using an aggregation pipeline with $replaceWith.]"
CodePudding user response:
Use a filter that also excludes documents having the status you want to add. This filter will match no documents if the status already exists in the array. The update operation will only be carried out if the status is not yet added:
var newStatusToAdd = ... // This is the new statusData document you want to add
filter := bson.M{
"_id": obId,
"statusData.status": bson.M{"$ne": p.Status},
}
update := bson.M{
"$push": bson.M{
"statusData": newStatusToAdd,
},
"$set": doc,
}
result, err := r.collection.UpdateOne(ctx, filter, update)
if err != nil {
// Handle error
return
}
if result.MatchedCount == 0 {
// The status already exists in statusData
} else if result.ModifiedCount == 1 {
// new status was added successfuly
}