如何使用Go语言更新MongoDB中嵌套数组的最后一个元素?

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

How to update last item of an embedded array in MongoDB using Go?

问题

我有一个具有以下结构的文档集合:

{
    "_id": ObjectId("..."),
    "rides": [
        {
            "status_history": ["status1", "status2", "status3"]
        },
        {
            "status_history": ["status4", "status5"]
        }
        ...
    ]
}

我想要做的是将新的状态追加到rides数组中最后一次骑行的status_history数组中,实现如下效果:

{
    "_id": ObjectId("..."),
    "rides": [
        {
            "status_history": ["status1", "status2", "status3"]
        },
        {
            "status_history": ["status4", "status5", "NEW_STATUS_HERE"]
        }
        ...
    ]
}

但我无法弄清楚如何做到这一点。我正在使用mongo-driver包连接到数据库。

以下是我设法编写的代码:

filter := bson.M{"_id": objectId}

arrayFilters := options.ArrayFilters{
	Filters: bson.A{
		bson.M{"s": bson.M{"rides": bson.A{"$slice", -1}}},
	},
}
upsert := true
opts := options.UpdateOptions{
	ArrayFilters: &arrayFilters,
	Upsert:       &upsert,
}
update := bson.M{
	"$push": bson.M{
		"rides.$
展开收缩
.status_history"
: statusEntry,
}, } result, err := col.UpdateOne(ctx, filter, update, &opts) fmt.Println(fmt.Sprintf( "Matched %v, Modified %v, Upserted %v", result.MatchedCount, result.ModifiedCount, result.UpsertedCount, ))

Println的输出是Matched 1, Modified 0, Upserted 0。确实,检查集合中的项显示它没有改变。

我在这里到底做错了什么?

英文:

I have a collection with documents with the following structure:

{
    "_id": ObjectId("..."),
    "rides": [
        {
            status_history: ["status1", "status2", "status3"]
        },
        {
            status_history: ["status4", "status5"]
        }
        ...
    ]
}

What I want to do is append a new status to the status_history array of the the last ride in the rides array, achieving something like:

{
    "_id": ObjectId("..."),
    "rides": [
        {
            status_history: ["status1", "status2", "status3"]
        },
        {
            status_history: ["status4", "status5", "NEW_STATUS_HERE"]
        }
        ...
    ]
}

But I can't quite figure out how to do that. I'm using the mongo-driver package to connect to the db.

Here's the code I managed to come up with:

filter := bson.M{"_id": objectId}

arrayFilters := options.ArrayFilters{
	Filters: bson.A{
		bson.M{"s": bson.M{"rides": bson.A{"$slice", -1}}},
	},
}
upsert := true
opts := options.UpdateOptions{
	ArrayFilters: &arrayFilters,
	Upsert:       &upsert,
}
update := bson.M{
	"$push": bson.M{
		"rides.$[s].status_history": statusEntry,
	},
}

result, err := col.UpdateOne(ctx, filter, update, &opts)

fmt.Println(fmt.Sprintf(
	"Matched %v, Modified %v, Upserted %v",
	result.MatchedCount,
	result.ModifiedCount,
	result.UpsertedCount,
))

The output of that Println is Matched 1, Modified 0, Upserted 0. Indeed, inspecting the item in the collection shows that it is unchanged.

What exactly am I getting wrong here?

答案1

得分: 1

查询

  • 管道更新需要 MongoDB >= 4.2
  • 查找数组的大小
  • 如果大小 > 1,则切片以获取 prv,否则 prv=[]
  • 将 prv 数组与 { "status": "array_with_new_member" } 连接

*我不使用 Go 语言,对于 Java,update 方法也接受管道,所以它的工作很简单,最坏的情况下,你可以将其用作 update 命令。

PlayMongo

update({},
[{ "$set": { "size": { "$size": "$rides" } } },
 { "$set":
  { "rides":
   { "$concatArrays":
    [{ "$cond":
      [{ "$gt": ["$size", 1] },
       { "$slice": ["$rides", 0, { "$subtract": ["$size", 1] }] }, []] },
     [{ "status_history":
       { "$concatArrays":
        [{ "$cond":
          [{ "$gt": ["$size", 0] },
           { "$arrayElemAt":
            ["$rides.status_history", { "$subtract": ["$size", 1] }] },
           []] }, ["new-status"]] }}]] }}},
  { "$unset": ["size"] }])
英文:

Query

  • pipeline update requires MongoDB >= 4.2
  • find the size of the array
  • if size>1 slice to get the prv else prv=[]
  • concat arrays prv with {"status" "array_with_new_member"}

*i dont use go, for Java the update method accepts a pipeline also,
so it works simple, in the worst case you can use it as update command.

PlayMongo

update({},
[{"$set":{"size":{"$size":"$rides"}}},
 {"$set":
  {"rides":
   {"$concatArrays":
    [{"$cond":
      [{"$gt":["$size", 1]},
       {"$slice":["$rides", 0, {"$subtract":["$size", 1]}]}, []]},
     [{"status_history":
       {"$concatArrays":
        [{"$cond":
          [{"$gt":["$size", 0]},
           {"$arrayElemAt":
            ["$rides.status_history", {"$subtract":["$size", 1]}]},
           []]}, ["new-status"]]}}]]}}},
  {"$unset":["size"]}])

答案2

得分: 1

这个使用聚合管道的更新操作(需要MongoDB v4.2或更高版本)将更新rides数组的最后一个元素(嵌套文档),并将新的_status_值添加到status_history数组字段中。更新操作在mongo shell中运行。

let NEW_VALUE = "new_status_999";

db.test.updateOne(
{ _id: 1 },
[
{ 
    $set: {
        rides: { 
            $concatArrays: [
                { $slice: [ "$rides", { $subtract: [ { $size: "$rides" }, 1 ] } ] },
                [ {
                    $let: {
                        vars: { lastEle: { $arrayElemAt: [ { $slice: [ "$rides", -1 ] }, 0 ] } }, 
                        in: {
                            $mergeObjects: [ 
                                "$$lastEle", 
                                { status_history: { $concatArrays: [ "$$lastEle.status_history", [ NEW_VALUE ] ] } } 
                            ]
                        }
                    }
                }]
            ]
        }
    }
}
])

更新后的文档:

{
        "_id" : 1,
        "rides" : [
                {
                        "status_history" : [
                                "status1",
                                "status2",
                                "status3"
                        ]
                },
                {
                        "status_history" : [
                                "status4",
                                "status5",
                                "new_status_999"    // <--- 更新结果
                        ]
                }
        ]
}
英文:

This Update With Aggregation Pipeline (feature requires MongoDB v4.2 or higher) will update the last element (nested document) of the rides array, with a new status value added to the status_history array field. The update runs in mongo shell.

let NEW_VALUE = &quot;new_status_999&quot;;

db.test.updateOne(
{ _id: 1 },
[
{ 
    $set: {
        rides: { 
            $concatArrays: [
                { $slice: [ &quot;$rides&quot;, { $subtract: [ { $size: &quot;$rides&quot; }, 1 ] } ] },
                [ {
                    $let: {
                        vars: { lastEle: { $arrayElemAt: [ { $slice: [ &quot;$rides&quot;, -1 ] }, 0 ] } }, 
                        in: {
                            $mergeObjects: [ 
                                &quot;$$lastEle&quot;, 
                                { status_history: { $concatArrays: [ &quot;$$lastEle.status_history&quot;, [ NEW_VALUE ] ] } } 
                            ]
                        }
                    }
                }]
            ]
        }
    }
}
])

The updated document:

{
        &quot;_id&quot; : 1,
        &quot;rides&quot; : [
                {
                        &quot;status_history&quot; : [
                                &quot;status1&quot;,
                                &quot;status2&quot;,
                                &quot;status3&quot;
                        ]
                },
                {
                        &quot;status_history&quot; : [
                                &quot;status4&quot;,
                                &quot;status5&quot;,
                                &quot;new_status_999&quot;    // &lt;--- the update result
                        ]
                }
        ]
}

huangapple
  • 本文由 发表于 2021年11月4日 05:01:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/69831670.html
匿名

发表评论

匿名网友

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

确定