检查值是否存在于一个对象数组中,使用Golang。

huangapple go评论67阅读模式
英文:

Check if value in an object array exist golang

问题

我正在尝试在将新值追加到MongoDB之前检查值是否存在,但每次都会出现错误。

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))

我的文档如下所示:

{
"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",
...
}

有不同的状态,我想确保在更新数据库之前不会多次将相同的状态发送到数据库中。

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

}

尝试更新

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 {
// 处理错误
return nil, errors.New(err.Error())
}
if result.MatchedCount == 0 {
// 状态已经存在于statusData中
} else if result.ModifiedCount == 1 {
// 新状态已成功添加
}

返回错误

"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.]"

英文:

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.]"

答案1

得分: 1

使用一个过滤器,同时排除具有您要添加的状态的文档。如果数组中已经存在该状态,该过滤器将不匹配任何文档。只有在状态尚未添加时,才会执行更新操作:

var newStatusToAdd = ... // 这是您要添加的新状态数据文档

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 {
    // 处理错误
    return
}
if result.MatchedCount == 0 {
    // 状态已经存在于statusData中
} else if result.ModifiedCount == 1 {
    // 新状态已成功添加
}

请注意,这是一个示例代码片段,其中的变量和上下文可能需要根据您的实际情况进行调整。

英文:

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
}

huangapple
  • 本文由 发表于 2022年11月27日 13:53:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/74587829.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定