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

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

Update values causing error golang mongodb

问题

我正在尝试更新我的Mongo文档,但是我一直遇到一个错误,我似乎无法理解这个错误。以下是我尝试做的事情:

  1. type UpdateCarpoolDTO struct {
  2. CarpoolID string `json:"carpoolId" bson:"carpoolId"`
  3. Passenger Passenger `bson:"passenger" json:"passenger"`
  4. }
  5. type Passenger struct {
  6. User User `bson:"user" json:"user"`
  7. NumberOfSeats int `json:"numberOfSeats" bson:"numberOfSeats"`
  8. Pickup Location `json:"pickup" bson:"pickup"`
  9. DropOff Location `json:"dropOff" bson:"dropOff"`
  10. DoorToDoorOption bool `bson:"doorToDoorOption" json:"doorToDoorOption"`
  11. LuggageSize string `bson:"luggageSize" json:"luggageSize"`
  12. }
  13. type Carpool struct {
  14. ID string `json:"id,omitempty" bson:"_id,omitempty"`
  15. SeatsAvailable int `json:"seatsAvailable" bson:"seatsAvailable"`
  16. Passengers []*Passenger `bson:"passengers" json:"passengers"`
  17. CreatedAt time.Time `json:"createdAt" bson:"createdAt"`
  18. UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"`
  19. ...
  20. }
  21. func (r *carpoolRepository) AddPassanger(dto *UpdateCarpoolDTO) (*Carpool, *errors.Error) {
  22. ctx, cancel := context.WithTimeout(context.Background(), mongoQueryTimeout)
  23. defer cancel()
  24. log.Println("THE DTO OBJ:::", dto)
  25. var result *Carpool
  26. filter := bson.M{"_id": dto.CarpoolID}
  27. update := bson.M{
  28. "$set": bson.M{
  29. "passangers": bson.M{
  30. "$push": dto.Passenger,
  31. },
  32. "seatsAvailable": bson.M{
  33. "$subtract": []interface{}{
  34. "$seatsAvailable",
  35. dto.Passenger.NumberOfSeats,
  36. },
  37. },
  38. },
  39. "$currentDate": bson.M{"updatedAt": true},
  40. }
  41. log.Println("THE DTO OBJ:::", "GOT HERE 1")
  42. options := options.FindOneAndUpdate().SetReturnDocument(1)
  43. log.Println("THE DTO OBJ:::", "GOT HERE 2")
  44. if err := r.collection.FindOneAndUpdate(ctx, filter, update, options).Decode(&result); err != nil {
  45. log.Println("THE DTO OBJ:::", "GOT HERE 3")
  46. if err == mongo.ErrNoDocuments {
  47. // failing here
  48. log.Println("THE DTO OBJ:::", "GOT HERE 4")
  49. return nil, errors.NewNotFoundError("request not found")
  50. }
  51. log.Println("THE DTO OBJ:::", "GOT HERE 5")
  52. log.Println("THE DTO OBJ 5 err:::", err.Error())
  53. return nil, errors.New(err.Error())
  54. }
  55. log.Println("THE DTO OBJ:::", "GOT HERE 6")
  56. return result, nil
  57. }

我用于调试的日志语句打印如下内容:

  1. 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
  2. THE DTO OBJ::: GOT HERE 1 2023/06/15 11:32:45
  3. THE DTO OBJ::: GOT HERE 2 2023/06/15 11:32:45
  4. THE DTO OBJ::: GOT HERE 3 2023/06/15 11:32:45
  5. THE DTO OBJ::: GOT HERE 5 2023/06/15 11:32:45
  6. 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

  1. type UpdateCarpoolDTO struct {
  2. CarpoolID string `json:&quot;carpoolId&quot; bson:&quot;carpoolId&quot;`
  3. Passenger Passenger `bson:&quot;passenger&quot; json:&quot;passenger&quot;`
  4. }
  5. type Passenger struct {
  6. User User `bson:&quot;user&quot; json:&quot;user&quot;`
  7. NumberOfSeats int `json:&quot;numberOfSeats&quot; bson:&quot;numberOfSeats&quot;`
  8. Pickup Location `json:&quot;pickup&quot; bson:&quot;pickup&quot;`
  9. DropOff Location `json:&quot;dropOff&quot; bson:&quot;dropOff&quot;`
  10. DoorToDoorOption bool `bson:&quot;doorToDoorOption&quot; json:&quot;doorToDoorOption&quot;`
  11. LuggageSize string `bson:&quot;luggageSize&quot; json:&quot;luggageSize&quot;`
  12. }
  13. type Carpool struct {
  14. ID string `json:&quot;id,omitempty&quot; bson:&quot;_id,omitempty&quot;`
  15. SeatsAvailable int `json:&quot;seatsAvailable&quot; bson:&quot;seatsAvailable&quot;`
  16. Passengers []*Passenger `bson:&quot;passengers&quot; json:&quot;passengers&quot;`
  17. CreatedAt time.Time `json:&quot;createdAt&quot; bson:&quot;createdAt&quot;`
  18. UpdatedAt time.Time `json:&quot;updatedAt&quot; bson:&quot;updatedAt&quot;`
  19. ...
  20. }
  21. func (r *carpoolRepository) AddPassanger(dto *UpdateCarpoolDTO) (*Carpool, *errors.Error) {
  22. ctx, cancel := context.WithTimeout(context.Background(), mongoQueryTimeout)
  23. defer cancel()
  24. log.Println(&quot;THE DTO OBJ:::&quot;, dto)
  25. var result *Carpool
  26. filter := bson.M{&quot;_id&quot;: dto.CarpoolID}
  27. update := bson.M{
  28. &quot;$set&quot;: bson.M{
  29. &quot;passangers&quot;: bson.M{
  30. &quot;$push&quot;: dto.Passenger,
  31. },
  32. &quot;seatsAvailable&quot;: bson.M{
  33. &quot;$subtract&quot;: []interface{}{
  34. &quot;$seatsAvailable&quot;,
  35. dto.Passenger.NumberOfSeats,
  36. },
  37. },
  38. },
  39. &quot;$currentDate&quot;: bson.M{&quot;updatedAt&quot;: true},
  40. }
  41. log.Println(&quot;THE DTO OBJ:::&quot;, &quot;GOT HERE 1&quot;)
  42. options := options.FindOneAndUpdate().SetReturnDocument(1)
  43. log.Println(&quot;THE DTO OBJ:::&quot;, &quot;GOT HERE 2&quot;)
  44. if err := r.collection.FindOneAndUpdate(ctx, filter, update, options).Decode(&amp;result); err != nil {
  45. log.Println(&quot;THE DTO OBJ:::&quot;, &quot;GOT HERE 3&quot;)
  46. if err == mongo.ErrNoDocuments {
  47. // failing here
  48. log.Println(&quot;THE DTO OBJ:::&quot;, &quot;GOT HERE 4&quot;)
  49. return nil, errors.NewNotFoundError(&quot;request not found&quot;)
  50. }
  51. log.Println(&quot;THE DTO OBJ:::&quot;, &quot;GOT HERE 5&quot;)
  52. log.Println(&quot;THE DTO OBJ 5 err:::&quot;, err.Error())
  53. return nil, errors.New(err.Error())
  54. }
  55. log.Println(&quot;THE DTO OBJ:::&quot;, &quot;GOT HERE 6&quot;)
  56. return result, nil
  57. }

The log statement I am using to debug prints the following

  1. 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
  2. THE DTO OBJ::: GOT HERE 1 2023/06/15 11:32:45
  3. THE DTO OBJ::: GOT HERE 2 2023/06/15 11:32:45
  4. THE DTO OBJ::: GOT HERE 3 2023/06/15 11:32:45
  5. THE DTO OBJ::: GOT HERE 5 2023/06/15 11:32:45
  6. 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方法进行聚合操作之间的区别。作为前提,我简化了一下代码,删除了结构体中的一些字段,并硬编码了一些值。如果我漏掉了什么,请告诉我,我会更新我的回答!首先,让我分享一下代码:

  1. package main
  2. import (
  3. "context"
  4. "fmt"
  5. "time"
  6. "go.mongodb.org/mongo-driver/bson"
  7. "go.mongodb.org/mongo-driver/mongo"
  8. "go.mongodb.org/mongo-driver/mongo/options"
  9. )
  10. type Passenger struct {
  11. NumberOfSeats int `json:"numberOfSeats" bson:"numberOfSeats"`
  12. DoorToDoorOption bool `bson:"doorToDoorOption" json:"doorToDoorOption"`
  13. LuggageSize string `bson:"luggageSize" json:"luggageSize"`
  14. }
  15. type Carpool struct {
  16. ID string `json:"id,omitempty" bson:"_id,omitempty"`
  17. SeatsAvailable int `json:"seatsAvailable" bson:"seatsAvailable"`
  18. Passengers []*Passenger `bson:"passengers" json:"passengers"`
  19. CreatedAt time.Time `json:"createdAt" bson:"createdAt"`
  20. UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"`
  21. }
  22. func main() {
  23. clientOptions := options.Client().ApplyURI("mongodb://root:root@localhost:27017")
  24. mongoClient, err := mongo.Connect(context.Background(), clientOptions)
  25. if err != nil {
  26. panic(err)
  27. }
  28. defer mongoClient.Disconnect(context.Background())
  29. appDB := mongoClient.Database("appDB")
  30. demoCollection := appDB.Collection("demoCollection")
  31. // clean up data - troubleshooting purposes
  32. defer func() {
  33. demoCollection.DeleteMany(context.Background(), bson.M{})
  34. }()
  35. // seed data
  36. carPool := &Carpool{
  37. ID: "1",
  38. SeatsAvailable: 4,
  39. Passengers: []*Passenger{
  40. {NumberOfSeats: 1, DoorToDoorOption: false, LuggageSize: "small"},
  41. },
  42. CreatedAt: time.Now(),
  43. UpdatedAt: time.Now(),
  44. }
  45. insertRes, err := demoCollection.InsertOne(context.Background(), carPool)
  46. if err != nil {
  47. panic(err)
  48. }
  49. // fetch data
  50. fmt.Println("before update")
  51. cursor, err := demoCollection.Find(context.Background(), bson.M{"_id": insertRes.InsertedID})
  52. if err != nil {
  53. panic(err)
  54. }
  55. var carPools []bson.M
  56. if err = cursor.All(context.Background(), &carPools); err != nil {
  57. panic(err)
  58. }
  59. for _, v := range carPools {
  60. fmt.Println(v)
  61. }
  62. // set data
  63. filter := bson.M{"_id": insertRes.InsertedID}
  64. update := bson.D{
  65. bson.E{
  66. Key: "$push",
  67. Value: bson.D{
  68. bson.E{
  69. Key: "passengers",
  70. Value: &Passenger{NumberOfSeats: 2, DoorToDoorOption: true, LuggageSize: "medium"},
  71. },
  72. },
  73. },
  74. }
  75. updateOptions := options.FindOneAndUpdate().SetReturnDocument(1)
  76. demoCollection.FindOneAndUpdate(context.Background(), filter, update, updateOptions)
  77. // aggregate update
  78. pipe := []bson.M{
  79. {
  80. "$addFields": bson.M{ // if the field already exists, it overwrites the value
  81. "seatsAvailable": bson.M{
  82. "$subtract": []string{"$seatsAvailable", "$seatsAvailable"},
  83. },
  84. },
  85. },
  86. }
  87. cursor, err = demoCollection.Aggregate(context.Background(), pipe)
  88. if err != nil {
  89. panic(err)
  90. }
  91. if err = cursor.All(context.Background(), &carPools); err != nil {
  92. panic(err)
  93. }
  94. fmt.Println("after update")
  95. for _, v := range carPools {
  96. fmt.Println(v)
  97. }
  98. }

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

更新

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

  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:

  1. package main
  2. import (
  3. &quot;context&quot;
  4. &quot;fmt&quot;
  5. &quot;time&quot;
  6. &quot;go.mongodb.org/mongo-driver/bson&quot;
  7. &quot;go.mongodb.org/mongo-driver/mongo&quot;
  8. &quot;go.mongodb.org/mongo-driver/mongo/options&quot;
  9. )
  10. type Passenger struct {
  11. NumberOfSeats int `json:&quot;numberOfSeats&quot; bson:&quot;numberOfSeats&quot;`
  12. DoorToDoorOption bool `bson:&quot;doorToDoorOption&quot; json:&quot;doorToDoorOption&quot;`
  13. LuggageSize string `bson:&quot;luggageSize&quot; json:&quot;luggageSize&quot;`
  14. }
  15. type Carpool struct {
  16. ID string `json:&quot;id,omitempty&quot; bson:&quot;_id,omitempty&quot;`
  17. SeatsAvailable int `json:&quot;seatsAvailable&quot; bson:&quot;seatsAvailable&quot;`
  18. Passengers []*Passenger `bson:&quot;passengers&quot; json:&quot;passengers&quot;`
  19. CreatedAt time.Time `json:&quot;createdAt&quot; bson:&quot;createdAt&quot;`
  20. UpdatedAt time.Time `json:&quot;updatedAt&quot; bson:&quot;updatedAt&quot;`
  21. }
  22. func main() {
  23. clientOptions := options.Client().ApplyURI(&quot;mongodb://root:root@localhost:27017&quot;)
  24. mongoClient, err := mongo.Connect(context.Background(), clientOptions)
  25. if err != nil {
  26. panic(err)
  27. }
  28. defer mongoClient.Disconnect(context.Background())
  29. appDB := mongoClient.Database(&quot;appDB&quot;)
  30. demoCollection := appDB.Collection(&quot;demoCollection&quot;)
  31. // clean up data - troubleshooting purposes
  32. defer func() {
  33. demoCollection.DeleteMany(context.Background(), bson.M{})
  34. }()
  35. // seed data
  36. carPool := &amp;Carpool{
  37. ID: &quot;1&quot;,
  38. SeatsAvailable: 4,
  39. Passengers: []*Passenger{
  40. {NumberOfSeats: 1, DoorToDoorOption: false, LuggageSize: &quot;small&quot;},
  41. },
  42. CreatedAt: time.Now(),
  43. UpdatedAt: time.Now(),
  44. }
  45. insertRes, err := demoCollection.InsertOne(context.Background(), carPool)
  46. if err != nil {
  47. panic(err)
  48. }
  49. // fetch data
  50. fmt.Println(&quot;before update&quot;)
  51. cursor, err := demoCollection.Find(context.Background(), bson.M{&quot;_id&quot;: insertRes.InsertedID})
  52. if err != nil {
  53. panic(err)
  54. }
  55. var carPools []bson.M
  56. if err = cursor.All(context.Background(), &amp;carPools); err != nil {
  57. panic(err)
  58. }
  59. for _, v := range carPools {
  60. fmt.Println(v)
  61. }
  62. // set data
  63. filter := bson.M{&quot;_id&quot;: insertRes.InsertedID}
  64. update := bson.D{
  65. bson.E{
  66. Key: &quot;$push&quot;,
  67. Value: bson.D{
  68. bson.E{
  69. Key: &quot;passengers&quot;,
  70. Value: &amp;Passenger{NumberOfSeats: 2, DoorToDoorOption: true, LuggageSize: &quot;medium&quot;},
  71. },
  72. },
  73. },
  74. }
  75. updateOptions := options.FindOneAndUpdate().SetReturnDocument(1)
  76. demoCollection.FindOneAndUpdate(context.Background(), filter, update, updateOptions)
  77. // aggregate update
  78. pipe := []bson.M{
  79. {
  80. &quot;$addFields&quot;: bson.M{ // if the field already exists, it overwrites the value
  81. &quot;seatsAvailable&quot;: bson.M{
  82. &quot;$subtract&quot;: []string{&quot;$seatsAvailable&quot;, &quot;$seatsAvailable&quot;},
  83. },
  84. },
  85. },
  86. }
  87. cursor, err = demoCollection.Aggregate(context.Background(), pipe)
  88. if err != nil {
  89. panic(err)
  90. }
  91. if err = cursor.All(context.Background(), &amp;carPools); err != nil {
  92. panic(err)
  93. }
  94. fmt.Println(&quot;after update&quot;)
  95. for _, v := range carPools {
  96. fmt.Println(v)
  97. }
  98. }

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:

确定