英文:
Update values causing error golang mongodb
问题
我正在尝试更新我的Mongo文档,但是我一直遇到一个错误,我似乎无法理解这个错误。以下是我尝试做的事情:
type UpdateCarpoolDTO struct {
CarpoolID string `json:"carpoolId" bson:"carpoolId"`
Passenger Passenger `bson:"passenger" json:"passenger"`
}
type Passenger struct {
User User `bson:"user" json:"user"`
NumberOfSeats int `json:"numberOfSeats" bson:"numberOfSeats"`
Pickup Location `json:"pickup" bson:"pickup"`
DropOff Location `json:"dropOff" bson:"dropOff"`
DoorToDoorOption bool `bson:"doorToDoorOption" json:"doorToDoorOption"`
LuggageSize string `bson:"luggageSize" json:"luggageSize"`
}
type Carpool struct {
ID string `json:"id,omitempty" bson:"_id,omitempty"`
SeatsAvailable int `json:"seatsAvailable" bson:"seatsAvailable"`
Passengers []*Passenger `bson:"passengers" json:"passengers"`
CreatedAt time.Time `json:"createdAt" bson:"createdAt"`
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"`
...
}
func (r *carpoolRepository) AddPassanger(dto *UpdateCarpoolDTO) (*Carpool, *errors.Error) {
ctx, cancel := context.WithTimeout(context.Background(), mongoQueryTimeout)
defer cancel()
log.Println("THE DTO OBJ:::", dto)
var result *Carpool
filter := bson.M{"_id": dto.CarpoolID}
update := bson.M{
"$set": bson.M{
"passangers": bson.M{
"$push": dto.Passenger,
},
"seatsAvailable": bson.M{
"$subtract": []interface{}{
"$seatsAvailable",
dto.Passenger.NumberOfSeats,
},
},
},
"$currentDate": bson.M{"updatedAt": true},
}
log.Println("THE DTO OBJ:::", "GOT HERE 1")
options := options.FindOneAndUpdate().SetReturnDocument(1)
log.Println("THE DTO OBJ:::", "GOT HERE 2")
if err := r.collection.FindOneAndUpdate(ctx, filter, update, options).Decode(&result); err != nil {
log.Println("THE DTO OBJ:::", "GOT HERE 3")
if err == mongo.ErrNoDocuments {
// failing here
log.Println("THE DTO OBJ:::", "GOT HERE 4")
return nil, errors.NewNotFoundError("request not found")
}
log.Println("THE DTO OBJ:::", "GOT HERE 5")
log.Println("THE DTO OBJ 5 err:::", err.Error())
return nil, errors.New(err.Error())
}
log.Println("THE DTO OBJ:::", "GOT HERE 6")
return result, nil
}
我用于调试的日志语句打印如下内容:
THE DTO OBJ::: &{91e7a42c-xxxx {{Ebene 0x14000392c00 Obey 5120000000 <nil>} 1 {312 Main St 3 43.xxx -79.xxxx Ontario Toronto N2J 223 Canada <nil>} {978 Elm St 2 43.xxxx -80.xxx Ontario Toronto 2B2 111 Canada <nil>} true MEDIUM}} 2023/06/15 11:32:45
THE DTO OBJ::: GOT HERE 1 2023/06/15 11:32:45
THE DTO OBJ::: GOT HERE 2 2023/06/15 11:32:45
THE DTO OBJ::: GOT HERE 3 2023/06/15 11:32:45
THE DTO OBJ::: GOT HERE 5 2023/06/15 11:32:45
THE DTO OBJ 5 err::: error decoding key seatsAvailable: cannot decode embedded document into an integer type
如有需要,可以提供更多代码。
英文:
I am trying to update my mongo document but I keep getting an error I cannot seem to wrap my head around the error.Here is what I am trying to do
type UpdateCarpoolDTO struct {
CarpoolID string `json:"carpoolId" bson:"carpoolId"`
Passenger Passenger `bson:"passenger" json:"passenger"`
}
type Passenger struct {
User User `bson:"user" json:"user"`
NumberOfSeats int `json:"numberOfSeats" bson:"numberOfSeats"`
Pickup Location `json:"pickup" bson:"pickup"`
DropOff Location `json:"dropOff" bson:"dropOff"`
DoorToDoorOption bool `bson:"doorToDoorOption" json:"doorToDoorOption"`
LuggageSize string `bson:"luggageSize" json:"luggageSize"`
}
type Carpool struct {
ID string `json:"id,omitempty" bson:"_id,omitempty"`
SeatsAvailable int `json:"seatsAvailable" bson:"seatsAvailable"`
Passengers []*Passenger `bson:"passengers" json:"passengers"`
CreatedAt time.Time `json:"createdAt" bson:"createdAt"`
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"`
...
}
func (r *carpoolRepository) AddPassanger(dto *UpdateCarpoolDTO) (*Carpool, *errors.Error) {
ctx, cancel := context.WithTimeout(context.Background(), mongoQueryTimeout)
defer cancel()
log.Println("THE DTO OBJ:::", dto)
var result *Carpool
filter := bson.M{"_id": dto.CarpoolID}
update := bson.M{
"$set": bson.M{
"passangers": bson.M{
"$push": dto.Passenger,
},
"seatsAvailable": bson.M{
"$subtract": []interface{}{
"$seatsAvailable",
dto.Passenger.NumberOfSeats,
},
},
},
"$currentDate": bson.M{"updatedAt": true},
}
log.Println("THE DTO OBJ:::", "GOT HERE 1")
options := options.FindOneAndUpdate().SetReturnDocument(1)
log.Println("THE DTO OBJ:::", "GOT HERE 2")
if err := r.collection.FindOneAndUpdate(ctx, filter, update, options).Decode(&result); err != nil {
log.Println("THE DTO OBJ:::", "GOT HERE 3")
if err == mongo.ErrNoDocuments {
// failing here
log.Println("THE DTO OBJ:::", "GOT HERE 4")
return nil, errors.NewNotFoundError("request not found")
}
log.Println("THE DTO OBJ:::", "GOT HERE 5")
log.Println("THE DTO OBJ 5 err:::", err.Error())
return nil, errors.New(err.Error())
}
log.Println("THE DTO OBJ:::", "GOT HERE 6")
return result, nil
}
The log statement I am using to debug prints the following
THE DTO OBJ::: &{91e7a42c-xxxx {{Ebene 0x14000392c00 Obey 5120000000 <nil>} 1 {312 Main St 3 43.xxx -79.xxxx Ontario Toronto N2J 223 Canada <nil>} {978 Elm St 2 43.xxxx -80.xxx Ontario Toronto 2B2 111 Canada <nil>} true MEDIUM}} 2023/06/15 11:32:45
THE DTO OBJ::: GOT HERE 1 2023/06/15 11:32:45
THE DTO OBJ::: GOT HERE 2 2023/06/15 11:32:45
THE DTO OBJ::: GOT HERE 3 2023/06/15 11:32:45
THE DTO OBJ::: GOT HERE 5 2023/06/15 11:32:45
THE DTO OBJ 5 err::: error decoding key seatsAvailable: cannot decode embedded document into an integer type
Further code is available on request.
答案1
得分: 0
我整理了一个小例子,展示了使用普通更新(使用FindOneAndUpdate
方法)和使用Aggregate
方法进行聚合操作之间的区别。作为前提,我简化了一下代码,删除了结构体中的一些字段,并硬编码了一些值。如果我漏掉了什么,请告诉我,我会更新我的回答!首先,让我分享一下代码:
package main
import (
"context"
"fmt"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
type Passenger struct {
NumberOfSeats int `json:"numberOfSeats" bson:"numberOfSeats"`
DoorToDoorOption bool `bson:"doorToDoorOption" json:"doorToDoorOption"`
LuggageSize string `bson:"luggageSize" json:"luggageSize"`
}
type Carpool struct {
ID string `json:"id,omitempty" bson:"_id,omitempty"`
SeatsAvailable int `json:"seatsAvailable" bson:"seatsAvailable"`
Passengers []*Passenger `bson:"passengers" json:"passengers"`
CreatedAt time.Time `json:"createdAt" bson:"createdAt"`
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"`
}
func main() {
clientOptions := options.Client().ApplyURI("mongodb://root:root@localhost:27017")
mongoClient, err := mongo.Connect(context.Background(), clientOptions)
if err != nil {
panic(err)
}
defer mongoClient.Disconnect(context.Background())
appDB := mongoClient.Database("appDB")
demoCollection := appDB.Collection("demoCollection")
// clean up data - troubleshooting purposes
defer func() {
demoCollection.DeleteMany(context.Background(), bson.M{})
}()
// seed data
carPool := &Carpool{
ID: "1",
SeatsAvailable: 4,
Passengers: []*Passenger{
{NumberOfSeats: 1, DoorToDoorOption: false, LuggageSize: "small"},
},
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
insertRes, err := demoCollection.InsertOne(context.Background(), carPool)
if err != nil {
panic(err)
}
// fetch data
fmt.Println("before update")
cursor, err := demoCollection.Find(context.Background(), bson.M{"_id": insertRes.InsertedID})
if err != nil {
panic(err)
}
var carPools []bson.M
if err = cursor.All(context.Background(), &carPools); err != nil {
panic(err)
}
for _, v := range carPools {
fmt.Println(v)
}
// set data
filter := bson.M{"_id": insertRes.InsertedID}
update := bson.D{
bson.E{
Key: "$push",
Value: bson.D{
bson.E{
Key: "passengers",
Value: &Passenger{NumberOfSeats: 2, DoorToDoorOption: true, LuggageSize: "medium"},
},
},
},
}
updateOptions := options.FindOneAndUpdate().SetReturnDocument(1)
demoCollection.FindOneAndUpdate(context.Background(), filter, update, updateOptions)
// aggregate update
pipe := []bson.M{
{
"$addFields": bson.M{ // if the field already exists, it overwrites the value
"seatsAvailable": bson.M{
"$subtract": []string{"$seatsAvailable", "$seatsAvailable"},
},
},
},
}
cursor, err = demoCollection.Aggregate(context.Background(), pipe)
if err != nil {
panic(err)
}
if err = cursor.All(context.Background(), &carPools); err != nil {
panic(err)
}
fmt.Println("after update")
for _, v := range carPools {
fmt.Println(v)
}
}
我只会详细介绍更新和聚合函数。
更新
更新功能分为以下几个部分:
- 设置用于获取要更新的文档的筛选器
- 设置
$push
操作符以将项添加到集合中 - 设置要添加的值
在这里没有要补充的内容。让我们转到聚合函数。
聚合
对于这个操作,你需要设置一个要使用的管道。这个管道在$addFields
阶段中使用。
请注意,如果你要添加一个已经存在的字段,它将被覆盖。我选择使用这个,因为我对此没有问题。
最后,你需要设置要使用的运算符(在这种情况下是$subtract
运算符),并提供一个表示要相减的数字的字符串数组。借助$subtract
运算符,你可以从第一个数字中减去第二个数字。
我添加了一些日志以进行演示。你可以很容易地看到代码更新了记录。
如果这有助于澄清你的问题,请告诉我,谢谢!
英文:
I put together a small example to show off the difference between a normal update (done with the method FindOneAndUpdate
) and an aggregate operation with the Aggregate
method. As a premise, I simplified a little bit the code by removing fields from the structs and hard-coding some values. If I missed something, just let me know and I'll update my answer!
First, let me share the code:
package main
import (
"context"
"fmt"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
type Passenger struct {
NumberOfSeats int `json:"numberOfSeats" bson:"numberOfSeats"`
DoorToDoorOption bool `bson:"doorToDoorOption" json:"doorToDoorOption"`
LuggageSize string `bson:"luggageSize" json:"luggageSize"`
}
type Carpool struct {
ID string `json:"id,omitempty" bson:"_id,omitempty"`
SeatsAvailable int `json:"seatsAvailable" bson:"seatsAvailable"`
Passengers []*Passenger `bson:"passengers" json:"passengers"`
CreatedAt time.Time `json:"createdAt" bson:"createdAt"`
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"`
}
func main() {
clientOptions := options.Client().ApplyURI("mongodb://root:root@localhost:27017")
mongoClient, err := mongo.Connect(context.Background(), clientOptions)
if err != nil {
panic(err)
}
defer mongoClient.Disconnect(context.Background())
appDB := mongoClient.Database("appDB")
demoCollection := appDB.Collection("demoCollection")
// clean up data - troubleshooting purposes
defer func() {
demoCollection.DeleteMany(context.Background(), bson.M{})
}()
// seed data
carPool := &Carpool{
ID: "1",
SeatsAvailable: 4,
Passengers: []*Passenger{
{NumberOfSeats: 1, DoorToDoorOption: false, LuggageSize: "small"},
},
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
insertRes, err := demoCollection.InsertOne(context.Background(), carPool)
if err != nil {
panic(err)
}
// fetch data
fmt.Println("before update")
cursor, err := demoCollection.Find(context.Background(), bson.M{"_id": insertRes.InsertedID})
if err != nil {
panic(err)
}
var carPools []bson.M
if err = cursor.All(context.Background(), &carPools); err != nil {
panic(err)
}
for _, v := range carPools {
fmt.Println(v)
}
// set data
filter := bson.M{"_id": insertRes.InsertedID}
update := bson.D{
bson.E{
Key: "$push",
Value: bson.D{
bson.E{
Key: "passengers",
Value: &Passenger{NumberOfSeats: 2, DoorToDoorOption: true, LuggageSize: "medium"},
},
},
},
}
updateOptions := options.FindOneAndUpdate().SetReturnDocument(1)
demoCollection.FindOneAndUpdate(context.Background(), filter, update, updateOptions)
// aggregate update
pipe := []bson.M{
{
"$addFields": bson.M{ // if the field already exists, it overwrites the value
"seatsAvailable": bson.M{
"$subtract": []string{"$seatsAvailable", "$seatsAvailable"},
},
},
},
}
cursor, err = demoCollection.Aggregate(context.Background(), pipe)
if err != nil {
panic(err)
}
if err = cursor.All(context.Background(), &carPools); err != nil {
panic(err)
}
fmt.Println("after update")
for _, v := range carPools {
fmt.Println(v)
}
}
I'll go into more detail only for the update and the aggregate function.
Update
The update feature is divided up into these parts:
- Set the filter for fetching the document to update
- Set the
$push
operator to add an item to a collection - Set the value to add
Nothing to add here. Let's switch to the Aggregate function.
Aggregate
For this operation, you've to set a pipeline to use. This pipeline is used in the $addFiels
stage.
> Please note that, if you're about to add an already-existent field this will be overwritten. I choose to use this because I'm fine with that.
Finally, you've to set the operator to use (in this case the $subtract
operator) and provide an array of strings that represents the numbers to be subtracted. Thanks to the $subtract
operator, you're able to subtract the second from the first one.
I added some logs for demo purposes. You can easily see that the record gets updated by the code.
Let me know if this helps clarifying your issue, thanks!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论