Вставить документ MongoDB из обработчика - PullRequest
1 голос
/ 05 января 2020

У меня есть код, и когда я пытаюсь это сделать, консоль вызова пишет undefined: insertContractData. Я пытаюсь изменить этот код, но получаю ошибку на Invalid memory address or nil pointer dereference Я не могу понять, как это сделать правильно.

Я думаю, что я не прав, напишите struct Я не могу это скомпилировать еще два дня, пожалуйста, что Я не так.

Я использую официальный драйвер Mon go - go для подключения к гордости языка, поэтому я не могу подключиться к самой Plaza более точно в качестве официального документа. Если это все мое, то оказалось подключено. И по отдельности, чтобы соединить каждую коллекцию, он не работает. Этот код должен вообще как-то начать работать, но работа не происходит, или, скорее, он работает неправильно, ругается на структуру, поэтому он скорее ругается на метод, который не названо Вот как это исправить, я не знаю, но я надеюсь, что есть некоторые решения этой проблемы Вот оно, спасибо за помощь.

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)
}

1 Ответ

4 голосов
/ 05 января 2020

Есть несколько проблем с вашим примером.

Во-первых, context.WithTimeout() возвращает вам context.Context и cancel функцию, которую вы ожидается, что он будет вызывать, предпочтительно с defer, чтобы убедиться, что выделенные ресурсы освобождены.

Далее, NewMyClient() отвечает за подключение к серверу MongoDB, но в вашем коде вы никогда не вызываете его. Вы должны назвать это в своем main().

В дальнейшем, в main() идентификатор insertContractData не определен. Скорее всего, вы захотите зарегистрировать метод mc.insertContractData в качестве обработчика (это значение метода btw).

Никогда не закрывайте соединение MongoDB, и уж точно не в конце ваш обработчик, и ни в вашей функции NewMyClient(). defer mc.mc.Disconnect(ctx) строк не только не нужны, они делают ваше приложение неработоспособным. mongo.Client предназначен для длительного проживания. Он имеет внутренний пул соединений, и его следует создать только один раз и использовать повторно из нескольких процедур. Он должен быть закрыт только при закрытии приложения.

Таким образом, ваша main() функция должна выглядеть следующим образом:

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() может выглядеть так:

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
}

И обработчик:

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)
    }
}

Теперь мы можем запустить это приложение.

Мы можем проверить его с помощью следующей команды curl:

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

И если мы подключимся к базе данных MongoDB и выполним db.test.find(), мы увидим следующие документы:

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