Vadim
Vadim

Reputation: 109

Insert MongoDB document from handler

I have code and when I try this call console write undefined: insertContractData. I try to change this code but get error on Invalid memory address or nil pointer dereference I can't to understand how to do it right.

I think what I not right write struct I can't this compile still two days please what I do not so.

I use the official Mongo-go driver to connect to the pride of the language, so I can’t connect to the Plaza itself more precisely as an official document. If it’s all mine, it turned out to be connected. And individually, to connect each collection, it doesn’t work This code should generally start to work somehow, but the work doesn’t happen, or rather it works incorrectly, swears at the structure, so it’s rather swears at a method that is not named Here’s how to fix it, I don’t know, but I hope there are some solutions to this issue Here it thanks for the help.

package main

import (
    "context"
    "encoding/json"
    "log"
    "net/http"
    "time"

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

type Data struct {
    Number    string `json:"number"`
    Driver    string `json:"driver"`
    Auto      string `json:"auto"`
    Tariff    string `json:"tariff"`
    Begindate string `json:"begindate"`
    Enddate   string `json:"enddate"`
    Continues bool   `json:"continues"`
    MoreInfo  string `json:"moreInfo"`
    Status    string `json:"status"`
}

type MyClient struct {
    mc *mongo.Client
    db *mongo.Database
}

func setupResponse(w http.ResponseWriter, req *http.Request) {
    (w).Header().Set("Access-Control-Allow-Origin", "*")
    (w).Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
    (w).Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
}

func NewMyClient(url, db string) (mc *MyClient, err error) {
    defer func() {
        if err != nil {
            mc = nil
        }
    }()
    mc = &MyClient{}
    if mc.mc, err = mongo.NewClient(options.Client().ApplyURI(url)); err != nil {
        return
    }
    ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
    err = mc.mc.Connect(ctx)
    if err != nil {
        log.Fatal(err)
    }
    defer mc.mc.Disconnect(ctx)
    mc.db = mc.mc.Database(db)
    return
}

func (mc *MyClient) insertContractData(w http.ResponseWriter, r *http.Request) {
    setupResponse(w, r)
    var err error
    var data Data
    err = json.NewDecoder(r.Body).Decode(&data)
    if err != nil {
        return
    }

    podcastsCollection := mc.db.Collection("test")
    ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
    defer mc.mc.Disconnect(ctx)
    _, err = podcastsCollection.InsertOne(ctx, bson.D{
        {"number", data.Number},
        {"driver", data.Driver},
        {"auto", data.Auto},
        {"tariff", data.Tariff},
        {"begindate", data.Begindate},
        {"enddate", data.Enddate},
        {"continues", data.Continues},
        {"moreInfo", data.MoreInfo},
        {"status", data.Status},
    })
    if err != nil {
        log.Fatal(err)
    }
}

func main() {
    var mc MyClient
    http.HandleFunc("/insertContractData", insertContractData)
    //http.HandleFunc("/selectContractData", selectContractData)
    http.ListenAndServe(":8081", nil)
}

Upvotes: 1

Views: 239

Answers (1)

icza
icza

Reputation: 417807

There are a handful of problems with your example.

First, context.WithTimeout() returns you a context.Context and a cancel function which you're expected to call, preferably with defer to make sure allocated resources are freed.

Next, NewMyClient() is responsible to connect to the MongoDB server, but in your code you never call it. You should call it in your main().

Going forward, in main() the insertContractData identifier is undefined. You most likely want to register the mc.insertContractData method as the handler (which is a method value btw).

You should never close the MongoDB connection, and certainly not at the end of your handler, and neither in your NewMyClient() function. defer mc.mc.Disconnect(ctx) lines are not only unneeded, they make your app disfunctional. mongo.Client is designed to be long-lived. It has an internal connection pool, and it should be created just once, and reused from multiple goroutines. It should only be closed on app shutdown.

So your main() function should look like this:

func main() {
    mc, err := NewMyClient("mongodb://localhost:27017", "someDB")
    if err != nil {
        panic(err)
    }
    http.HandleFunc("/insertContractData", mc.insertContractData)
    panic(http.ListenAndServe(":8081", nil))
}

NewMyClient() could look like this:

func NewMyClient(url, db string) (mc *MyClient, err error) {
    mc = &MyClient{}
    if mc.mc, err = mongo.NewClient(options.Client().ApplyURI(url)); err != nil {
        return
    }
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()
    err = mc.mc.Connect(ctx)
    if err != nil {
        log.Fatal(err)
    }
    mc.db = mc.mc.Database(db)
    return
}

And the handler:

func (mc *MyClient) insertContractData(w http.ResponseWriter, r *http.Request) {
    setupResponse(w, r)
    var err error
    var data Data
    err = json.NewDecoder(r.Body).Decode(&data)
    if err != nil {
        fmt.Println(err)
        return
    }

    podcastsCollection := mc.db.Collection("test")
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()
    _, err = podcastsCollection.InsertOne(ctx, bson.D{
        {"number", data.Number},
        {"driver", data.Driver},
        {"auto", data.Auto},
        {"tariff", data.Tariff},
        {"begindate", data.Begindate},
        {"enddate", data.Enddate},
        {"continues", data.Continues},
        {"moreInfo", data.MoreInfo},
        {"status", data.Status},
    })
    if err != nil {
        log.Fatal(err)
    }
}

Now we can run this app.

We may test it with the following curl command:

curl -d '{"number":"11","driver":"dr1","status":"s1"}' -X POST http://localhost:8081/insertContractData

And if we connect to the MongoDB database, and execute db.test.find(), we'll see the following documents:

{ "_id" : ObjectId("5e123e6c1618bd4c80a2e13f"), "number" : "11", "driver" : "dr1", "auto" : "", "tariff" : "", "begindate" : "", "enddate" : "", "continues" : false, "moreInfo" : "", "status" : "s1" }

Upvotes: 4

Related Questions