$pull 在带有 mongo-driver 的 Go 和 Mongosh 中的工作方式不同
$pull doesn't work the same in Go with mongo-driver and in Mongosh
什么?
正在尝试从 mongo 文档中的对象数组中删除一个元素。
我使用:
go 版本 go1.17.1 darwin/amd64;
go.mongodb.org/mongo-driver v 1.8.4;
MongoDB 5.0.6 企业版
函数的简化版本,一切都尽可能简单:
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)
}
预期:
带有我提供的 ID 的文档将不再包含数组“数据”中的元素,这些元素的字段“field_type”等于“field_type_1”或“field_type_2”
得到:
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>}
通过 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 }
元素从数组中消失了。
为什么会这样?
我确实注意到原生查询有单个大括号(只是一个对象),而 Go 代码使用 bson.D 从技术上讲,它是那些相同对象的数组 (bson.E) -> [{ }].
我尝试更改 mongosh 命令来测试:
db.templates.updateOne(
{ _id: ObjectId("6228a89d621d19a2f7977d2f") },
[{ $pull: { data: {field_type: {$in: ["field_type_1", "field_type_2"]}}}
}]
)
MongoServerError: Unrecognized pipeline stage name: '$pull'
在 Go 中,我尝试使用 bson.E 而不是 bson.D(尽管根据文档建议将后者用于命令)并得到了这个:
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
bson.D
为文档建模,其中包含 key-value 对的有序列表,其中 key 是 属性 名称,value 是 属性 的值。
因此,如果您打算使用 bson.D
对文档建模,您总是必须在等效的 shell 命令中有一个文档的地方编写一个 bson.D
复合文字。
因此您的 update
文档必须如下所示:
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"},
}}},
}},
}},
}
如果您从复合文字中省略命名字段,它将简化为:
update := bson.D{
{"$pull", bson.D{{
"data", bson.D{{
"field_type", bson.D{{
"$in", []string{"field_type_1", "field_type_2"},
}}},
}},
}},
}
是的,有点丑。请注意,如果元素的顺序无关紧要,使用 bson.M
values to define documents (it's a map). For details, see
会容易得多
您的 update
可能看起来像这样定义 bson.M
:
update := bson.M{
"$pull": bson.M{
"data": bson.M{
"field_type": bson.M{
"$in": []string{"field_type_1", "field_type_2"},
},
},
},
}
什么?
正在尝试从 mongo 文档中的对象数组中删除一个元素。
我使用: go 版本 go1.17.1 darwin/amd64; go.mongodb.org/mongo-driver v 1.8.4; MongoDB 5.0.6 企业版
函数的简化版本,一切都尽可能简单:
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)
}
预期:
带有我提供的 ID 的文档将不再包含数组“数据”中的元素,这些元素的字段“field_type”等于“field_type_1”或“field_type_2”
得到:
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>}
通过 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 }
元素从数组中消失了。
为什么会这样?
我确实注意到原生查询有单个大括号(只是一个对象),而 Go 代码使用 bson.D 从技术上讲,它是那些相同对象的数组 (bson.E) -> [{ }].
我尝试更改 mongosh 命令来测试:
db.templates.updateOne(
{ _id: ObjectId("6228a89d621d19a2f7977d2f") },
[{ $pull: { data: {field_type: {$in: ["field_type_1", "field_type_2"]}}}
}]
)
MongoServerError: Unrecognized pipeline stage name: '$pull'
在 Go 中,我尝试使用 bson.E 而不是 bson.D(尽管根据文档建议将后者用于命令)并得到了这个:
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
bson.D
为文档建模,其中包含 key-value 对的有序列表,其中 key 是 属性 名称,value 是 属性 的值。
因此,如果您打算使用 bson.D
对文档建模,您总是必须在等效的 shell 命令中有一个文档的地方编写一个 bson.D
复合文字。
因此您的 update
文档必须如下所示:
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"},
}}},
}},
}},
}
如果您从复合文字中省略命名字段,它将简化为:
update := bson.D{
{"$pull", bson.D{{
"data", bson.D{{
"field_type", bson.D{{
"$in", []string{"field_type_1", "field_type_2"},
}}},
}},
}},
}
是的,有点丑。请注意,如果元素的顺序无关紧要,使用 bson.M
values to define documents (it's a map). For details, see
您的 update
可能看起来像这样定义 bson.M
:
update := bson.M{
"$pull": bson.M{
"data": bson.M{
"field_type": bson.M{
"$in": []string{"field_type_1", "field_type_2"},
},
},
},
}