英文:
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 命令。
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.
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 = "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 ] ] } }
]
}
}
}]
]
}
}
}
])
The updated document:
{
"_id" : 1,
"rides" : [
{
"status_history" : [
"status1",
"status2",
"status3"
]
},
{
"status_history" : [
"status4",
"status5",
"new_status_999" // <--- the update result
]
}
]
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论