Search code examples
gomgogo-gin

What is the correct way to save post data (with integer and string values) in the database golang?


I've the following golang code:

package main

import (
    "github.com/gin-gonic/gin"
    "gopkg.in/mgo.v2"
    "gopkg.in/mgo.v2/bson"
    "log"
    "time"
)

func main() {
    router := gin.Default()
    router.POST("/save-address", SaveAddress)
    router.Run()
}

func SaveAddress(c *gin.Context){
    var err error
    conditions := bson.M{}
    c.Request.ParseForm()
    for key, _ := range c.Request.PostForm {
        if key != "id"{
            conditions[key] = c.PostForm(key)
        }
    }
    conditions["_id"] = 1
    mongoSession := ConnectDb()

    sessionCopy := mongoSession.Copy()
    defer sessionCopy.Close()

    getCollection := mongoSession.DB("bformssettings").C("address")
    err = getCollection.Insert(conditions)
    if err != nil{
        println(err)
    }else{
        println("Data saved successfully!!!")
    }
}
func ConnectDb() (mongoSession *mgo.Session) {
    mongoDBDialInfo := &mgo.DialInfo{
        Addrs:    []string{"localhost:27017"},
        Timeout:  60 * time.Second,
        Database: "bformssettings",
    }

    mongoSession, err := mgo.DialWithInfo(mongoDBDialInfo)
    if err != nil {
        log.Fatalf("CreateSession: %s\n", err)
    }

    mongoSession.SetMode(mgo.Monotonic, true)

    return mongoSession
}

When I run the code, data of the following format will be saved in the database:

{ "_id" : 1, "customer_id" : "3", "address" : "Chicago, IL", "city" : "Chicago", "state" : "IL", "zipcode" : "60647" }

Problem:

customer_id is an integer value, but it will be saved as string in the database.

Possible workaround:

It is possible to reconvert the string representation of id back to integer before saving it in the database.

Question:

Is there another way to save data as it is? E.g. to save integer values as integer values?


Solution

  • If you look at your saved document, you can see it's _id property is already a number (and not a string), so yes, this is definitely possible.

    The reason why you end up with a customer_id property being of type string is because the document you save (conditions variable) holds a string value for customer_id property. And it is of type string because you filled it with the return value of Context.PostForm() which returns a form value as a string.

    If you want it to be an integer in the database, convert it to a Go integer before setting it in conditions. For that you may use strconv.Atoi() for example.

    for key, _ := range c.Request.PostForm {
        value := c.PostForm(key)
        if key == "customer_id" {
            if id, err := strconv.Atoi(value); err != nil {
                // Not a valid number, handle error
            } else {
                conditions[key] = id
            }
        } else {
            if key != "id"{
                conditions[key] = value
            }
        }
    }
    

    You have to define somehow which fields are supposed to hold integer values. I just showed a way to do that with a single field. If you have multiple of them, you may list them in a slice, and use a single for loop to detect / handle all; or even better, put them in a map that acts as a set, and you can detect these fields without a for loop.

    Another option would be to create a struct type modeling your form input data, and use a library like Gorilla's schema to unmarshal into that struct in a type-aware manner.