更新导致错误的值,Golang MongoDB。

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

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:&quot;carpoolId&quot; bson:&quot;carpoolId&quot;`
Passenger Passenger `bson:&quot;passenger&quot; json:&quot;passenger&quot;`
}
type Passenger struct {
User             User     `bson:&quot;user&quot; json:&quot;user&quot;`
NumberOfSeats    int      `json:&quot;numberOfSeats&quot; bson:&quot;numberOfSeats&quot;`
Pickup           Location `json:&quot;pickup&quot; bson:&quot;pickup&quot;`
DropOff          Location `json:&quot;dropOff&quot; bson:&quot;dropOff&quot;`
DoorToDoorOption bool     `bson:&quot;doorToDoorOption&quot; json:&quot;doorToDoorOption&quot;`
LuggageSize      string   `bson:&quot;luggageSize&quot; json:&quot;luggageSize&quot;`
}
type Carpool struct {
ID               string         `json:&quot;id,omitempty&quot; bson:&quot;_id,omitempty&quot;`
SeatsAvailable   int            `json:&quot;seatsAvailable&quot; bson:&quot;seatsAvailable&quot;`
Passengers       []*Passenger   `bson:&quot;passengers&quot; json:&quot;passengers&quot;`
CreatedAt        time.Time      `json:&quot;createdAt&quot; bson:&quot;createdAt&quot;`
UpdatedAt        time.Time      `json:&quot;updatedAt&quot; bson:&quot;updatedAt&quot;`
...
}
func (r *carpoolRepository) AddPassanger(dto *UpdateCarpoolDTO) (*Carpool, *errors.Error) {
ctx, cancel := context.WithTimeout(context.Background(), mongoQueryTimeout)
defer cancel()
log.Println(&quot;THE DTO OBJ:::&quot;, dto)
var result *Carpool
filter := bson.M{&quot;_id&quot;: dto.CarpoolID}
update := bson.M{
&quot;$set&quot;: bson.M{
&quot;passangers&quot;: bson.M{
&quot;$push&quot;: dto.Passenger,
},
&quot;seatsAvailable&quot;: bson.M{
&quot;$subtract&quot;: []interface{}{
&quot;$seatsAvailable&quot;,
dto.Passenger.NumberOfSeats,
},
},
},
&quot;$currentDate&quot;: bson.M{&quot;updatedAt&quot;: true},
}
log.Println(&quot;THE DTO OBJ:::&quot;, &quot;GOT HERE 1&quot;)
options := options.FindOneAndUpdate().SetReturnDocument(1)
log.Println(&quot;THE DTO OBJ:::&quot;, &quot;GOT HERE 2&quot;)
if err := r.collection.FindOneAndUpdate(ctx, filter, update, options).Decode(&amp;result); err != nil {
log.Println(&quot;THE DTO OBJ:::&quot;, &quot;GOT HERE 3&quot;)
if err == mongo.ErrNoDocuments {
// failing here
log.Println(&quot;THE DTO OBJ:::&quot;, &quot;GOT HERE 4&quot;)
return nil, errors.NewNotFoundError(&quot;request not found&quot;)
}
log.Println(&quot;THE DTO OBJ:::&quot;, &quot;GOT HERE 5&quot;)
log.Println(&quot;THE DTO OBJ 5 err:::&quot;, err.Error())
return nil, errors.New(err.Error())
}
log.Println(&quot;THE DTO OBJ:::&quot;, &quot;GOT HERE 6&quot;)
return result, nil
}

The log statement I am using to debug prints the following

THE DTO OBJ::: &amp;{91e7a42c-xxxx {{Ebene  0x14000392c00 Obey 5120000000 &lt;nil&gt;} 1 {312 Main St 3 43.xxx -79.xxxx Ontario Toronto N2J 223 Canada &lt;nil&gt;} {978 Elm St 2 43.xxxx -80.xxx Ontario Toronto 2B2 111 Canada &lt;nil&gt;} 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)
	}
}

我只会详细介绍更新和聚合函数。

更新

更新功能分为以下几个部分:

  1. 设置用于获取要更新的文档的筛选器
  2. 设置$push操作符以将项添加到集合中
  3. 设置要添加的值

在这里没有要补充的内容。让我们转到聚合函数。

聚合

对于这个操作,你需要设置一个要使用的管道。这个管道在$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 (
	&quot;context&quot;
	&quot;fmt&quot;
	&quot;time&quot;

	&quot;go.mongodb.org/mongo-driver/bson&quot;
	&quot;go.mongodb.org/mongo-driver/mongo&quot;
	&quot;go.mongodb.org/mongo-driver/mongo/options&quot;
)

type Passenger struct {
	NumberOfSeats    int    `json:&quot;numberOfSeats&quot; bson:&quot;numberOfSeats&quot;`
	DoorToDoorOption bool   `bson:&quot;doorToDoorOption&quot; json:&quot;doorToDoorOption&quot;`
	LuggageSize      string `bson:&quot;luggageSize&quot; json:&quot;luggageSize&quot;`
}

type Carpool struct {
	ID             string       `json:&quot;id,omitempty&quot; bson:&quot;_id,omitempty&quot;`
	SeatsAvailable int          `json:&quot;seatsAvailable&quot; bson:&quot;seatsAvailable&quot;`
	Passengers     []*Passenger `bson:&quot;passengers&quot; json:&quot;passengers&quot;`
	CreatedAt      time.Time    `json:&quot;createdAt&quot; bson:&quot;createdAt&quot;`
	UpdatedAt      time.Time    `json:&quot;updatedAt&quot; bson:&quot;updatedAt&quot;`
}

func main() {
	clientOptions := options.Client().ApplyURI(&quot;mongodb://root:root@localhost:27017&quot;)
	mongoClient, err := mongo.Connect(context.Background(), clientOptions)
	if err != nil {
		panic(err)
	}
	defer mongoClient.Disconnect(context.Background())

	appDB := mongoClient.Database(&quot;appDB&quot;)
	demoCollection := appDB.Collection(&quot;demoCollection&quot;)

	// clean up data - troubleshooting purposes
	defer func() {
		demoCollection.DeleteMany(context.Background(), bson.M{})
	}()

	// seed data
	carPool := &amp;Carpool{
		ID:             &quot;1&quot;,
		SeatsAvailable: 4,
		Passengers: []*Passenger{
			{NumberOfSeats: 1, DoorToDoorOption: false, LuggageSize: &quot;small&quot;},
		},
		CreatedAt: time.Now(),
		UpdatedAt: time.Now(),
	}
	insertRes, err := demoCollection.InsertOne(context.Background(), carPool)
	if err != nil {
		panic(err)
	}

	// fetch data
	fmt.Println(&quot;before update&quot;)
	cursor, err := demoCollection.Find(context.Background(), bson.M{&quot;_id&quot;: insertRes.InsertedID})
	if err != nil {
		panic(err)
	}
	var carPools []bson.M
	if err = cursor.All(context.Background(), &amp;carPools); err != nil {
		panic(err)
	}
	for _, v := range carPools {
		fmt.Println(v)
	}

	// set data
	filter := bson.M{&quot;_id&quot;: insertRes.InsertedID}
	update := bson.D{
		bson.E{
			Key: &quot;$push&quot;,
			Value: bson.D{
				bson.E{
					Key:   &quot;passengers&quot;,
					Value: &amp;Passenger{NumberOfSeats: 2, DoorToDoorOption: true, LuggageSize: &quot;medium&quot;},
				},
			},
		},
	}
	updateOptions := options.FindOneAndUpdate().SetReturnDocument(1)
	demoCollection.FindOneAndUpdate(context.Background(), filter, update, updateOptions)

	// aggregate update
	pipe := []bson.M{
		{
			&quot;$addFields&quot;: bson.M{ // if the field already exists, it overwrites the value
				&quot;seatsAvailable&quot;: bson.M{
					&quot;$subtract&quot;: []string{&quot;$seatsAvailable&quot;, &quot;$seatsAvailable&quot;},
				},
			},
		},
	}
	cursor, err = demoCollection.Aggregate(context.Background(), pipe)
	if err != nil {
		panic(err)
	}
	if err = cursor.All(context.Background(), &amp;carPools); err != nil {
		panic(err)
	}
	fmt.Println(&quot;after update&quot;)
	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:

  1. Set the filter for fetching the document to update
  2. Set the $push operator to add an item to a collection
  3. 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!

huangapple
  • 本文由 发表于 2023年6月15日 23:40:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/76483338.html
匿名

发表评论

匿名网友

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

确定