2

I'm learning Go and Gin framework. I built a simple microservice connected to a MongoDB collection, everything works but when I add a document using a POST it adds the "id" field instead of generating the key "_id" field, is there a way to avoid this?

This is my func:

func (r *Rest) CreatePost(c *gin.Context) {
var postCollection = database.GetCollection(r.db, "GoDB")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
post := new(model.Post)
defer cancel()

if err := c.ShouldBindJSON(&post); err != nil {
    c.JSON(http.StatusBadRequest, gin.H{"message": err})
    log.Fatal(err)
    return
}

// validation
if err := post.Validate(); err == nil {
    c.JSON(http.StatusOK, gin.H{"input": "valid"})
} else {
    c.JSON(http.StatusBadRequest, gin.H{"input validation": err.Error()})
    return
}

postPayload := model.Post{
    ID:      primitive.NewObjectID(),
    Title:   post.Title,
    Article: post.Article,
}

result, err := postCollection.InsertOne(ctx, postPayload)

if err != nil {
    c.JSON(http.StatusInternalServerError, gin.H{"message": err})
    return
}

c.JSON(http.StatusOK, gin.H{"message": "Posted succesfully", "Data": 
map[string]interface{}{"data": result}})
}

This is my model:

type Post struct {
ID      primitive.ObjectID
Title   string `validate:"required,gte=2,lte=20"`
Article string `validate:"required,gte=4,lte=40"`
}

To understand this is the returned doc from Mongo

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189

1 Answers1

0

By default, the key for ID is id. You should use the bson tag to generate the key _id instead.

type Post struct {
    ID      primitive.ObjectID `bson:"_id"`
    Title   string             `validate:"required,gte=2,lte=20"`
    Article string             `validate:"required,gte=4,lte=40"`
}

Here is the doc:

When marshalling a struct, each field will be lowercased to generate the key for the corresponding BSON element. For example, a struct field named "Foo" will generate key "foo". This can be overridden via a struct tag (e.g. bson:"fooField" to generate key "fooField" instead).

When the document does not contain an element named _id, the driver will add one automatically (see the source code):

// ensureID inserts the given ObjectID as an element named "_id" at the
// beginning of the given BSON document if there is not an "_id" already. If
// there is already an element named "_id", the document is not modified. It
// returns the resulting document and the decoded Go value of the "_id" element.
func ensureID(
    doc bsoncore.Document,
    oid primitive.ObjectID,
    bsonOpts *options.BSONOptions,
    reg *bsoncodec.Registry,
) (bsoncore.Document, interface{}, error) {

Here is a demo:

package main

import (
    "context"

    "go.mongodb.org/mongo-driver/bson/primitive"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
)

type Post struct {
    ID      primitive.ObjectID `bson:"_id"`
    Title   string             `validate:"required,gte=2,lte=20"`
    Article string             `validate:"required,gte=4,lte=40"`
}

func main() {
    client, err := mongo.Connect(context.Background(), options.Client().ApplyURI("mongodb://localhost"))
    if err != nil {
        panic(err)
    }

    postCollection := client.Database("demo").Collection("posts")
    post := Post{
        ID:      primitive.NewObjectID(),
        Title:   "test title",
        Article: "test content",
    }
    if err != nil {
        panic(err)
    }

    if _, err = postCollection.InsertOne(context.Background(), post); err != nil {
        panic(err)
    }
}

And the document created in the database:

demo> db.posts.find()
[
  {
    _id: ObjectId("64a53bcbb7be31ae42e6c00c"),
    title: 'test title',
    article: 'test content'
  }
]
Zeke Lu
  • 6,349
  • 1
  • 17
  • 23
  • I tried it and it generates the "_id" field as usual, but the "id" field results unset. –  Jul 05 '23 at 10:16
  • 1
    @Fastasf Use `mongo` or `mongosh` to see what the documents are. Do not use the IDE because it displays tabular data and you can not tell whether the `id` field is empty or it does not exist at all. – Zeke Lu Jul 05 '23 at 10:19
  • I'm using Jetbrain's DataGrip –  Jul 05 '23 at 10:20
  • 1
    If you want the document to use the field name `id` instead of `_id`. That's impossible. Because MongoDB will add the `_id` field if the document does not contain it. See https://www.mongodb.com/docs/manual/reference/method/db.collection.insert/#_id-field. – Zeke Lu Jul 05 '23 at 10:22
  • Thx for ur time, I thought it could be modified! –  Jul 05 '23 at 10:31