Golang學習系列第六天:操作MongoDB

dongguangming發表於2020-07-24

可以直接到MongoDB官網docs.mongodb.com/manual/tutorial/i...根據樣板安裝:,可根據自己的電腦作業系統下載對應的版本,我下載的是mongodb-linux-x86_64-4.0.0.tgz安裝包,不過也可以直接點選下面這個連結直接下載 fastdl.mongodb.org/linux/mongodb-l...,即

wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-4.0.0.tgz

下載完畢後解壓縮

[root@master dgm]# tar -zxf mongodb-linux-x86_64-4.0.0.tgz

名字那麼長,可以進行重新命名:

[root@master dgm]# mv mongodb-linux-x86_64-4.0.0 mongodb

進入到mongodb主目錄下:

cd mongodb

分別建配置檔案、資料目錄、日誌檔案

建立配置檔案

vim mongodb.conf

鍵入以下內容

#埠號
port=27017
#db目錄
dbpath=/dgm/mongodb/data/db
#日誌目錄
logpath=/dgm/mongodb/logs/mongodb.log
#後臺
fork=true
#日誌輸出
logappend=true
#允許遠端IP連線
bind_ip=0.0.0.0

注意路徑根據自己電腦的實際情況填寫

建立資料目錄和日誌檔案

[root@master mongodb]# mkdir -p data/db logs
[root@master mongodb]# touch logs/mongodb.log

編輯環境配置

vim /etc/profile

追加以下內容:

切記路徑按實際情況寫

source /etc/profile

啟動mongodb測試

[root@master mongodb]# mongod --config mongodb.conf 

最後連線測試

[root@master mongodb]# mongo

為了安全起見,我們需要設定相應的使用者名稱和密碼。

建立資料庫系統管理員

> use admin
switched to db admin
> db.createUser({ user: "admin", pwd: "12345678", roles: [{ role: "userAdminAnyDatabase", db: "admin" }] })
Successfully added user: {
    "user" : "admin",
    "roles" : [
        {
            "role" : "userAdminAnyDatabase",
            "db" : "admin"
        }
    ]
}
> db.auth("admin", "12345678")
1

修改mongodb配置追加認證標誌

## 是否以安全認證方式執行,預設是不認證的非安全方式
#noauth = true
auth = true

然後重啟mongodb服務

再次通過shell進入mongodb,建立需要管理的mongodb 資料的賬號密碼,此處是庫是douyin,使用者名稱是root,密碼87654321

[root@master mongorest]# mongo
> use admin
switched to db admin
> db.auth("admin", "12345678")
1
> use douyin
switched to db douyin
> db.createUser({ user: "root", pwd: "87654321", roles: [{ role: "dbOwner", db: "douyin" }] })
Successfully added user: {
    "user" : "root",
    "roles" : [
        {
            "role" : "dbOwner",
            "db" : "douyin"
        }
    ]
}
> use admin
switched to db admin
> db.system.users.find()
{ "_id" : "admin.admin", "user" : "admin", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "Qp+6YETcIsDyrPPwQVtWHQ==", "storedKey" : "0X27QePHJknrd+5qg4Ai5TeEWjg=", "serverKey" : "ZYRXkrQfJY875GC1qf76xAmBFow=" }, "SCRAM-SHA-256" : { "iterationCount" : 15000, "salt" : "E3LYqVegf93pTNjwNqXh4Gy8zQ1qNXXz0HtHHw==", "storedKey" : "yUZq7I9/w8Kf6fLu6Q8OqJcKNv77KUDmvGo4gEGi5ng=", "serverKey" : "+sNL0T/gfa+B+HoNSeid+HCC7OulvZlvSi2FDtE3wfk=" } }, "roles" : [ { "role" : "userAdminAnyDatabase", "db" : "admin" } ] }
{ "_id" : "douyin.root", "user" : "root", "db" : "douyin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "gVHTUMMMC38slLBW15kxPw==", "storedKey" : "591b17pCtkEZcVXf7ZO/Ll4DPAs=", "serverKey" : "vd5w+StBi9eXfViwWY30tc66lmo=" }, "SCRAM-SHA-256" : { "iterationCount" : 15000, "salt" : "2CHwq56N9MLts2v+PSqN3qs6tpWX1BKHY0aTDA==", "storedKey" : "2v5I/nnNoGVst2tTljoQs34z7bDNZS4euv6nAFZGxyc=", "serverKey" : "/F2xcR86DH4ErEEEbDyprmm1ttnl1o6sniWrj3vjjTY=" } }, "roles" : [ { "role" : "dbOwner", "db" : "douyin" } ] }
> exit

測試密碼許可權是否生效

先看失敗的嘗試案例

[root@master mongorest]# mongo
MongoDB shell version v4.0.0
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 4.0.0
> use douyin
switched to db douyin
> show collections
Warning: unable to run listCollections, attempting to approximate collection names by parsing connectionStatus
> db.douyin.find()
Error: error: {
    "ok" : 0,
    "errmsg" : "command find requires authentication",
    "code" : 13,
    "codeName" : "Unauthorized"
}
> 

再看成功的案例

[root@master mongorest]# mongo "mongodb://root:87654321@127.0.0.1:27017/douyin"
MongoDB shell version v4.0.0
connecting to: mongodb://127.0.0.1:27017/douyin
MongoDB server version: 4.0.0
> show collections
douyin
> db.douyin.find()
{ "_id" : ObjectId("5f083625b8b307c7e889f276") }
{ "_id" : ObjectId("5f08365cb8b307c7e889f277"), "name" : "dongguangming", "age" : 31 }
> 

很好,許可權認證通過了,可以查詢資料記錄

2.1 增加書籍介面

新建go檔案mongdb-add.go,鍵入以下程式碼

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"

    "goji.io"
    "goji.io/pat"
    "gopkg.in/mgo.v2"
)

func ErrorWithJSON(w http.ResponseWriter, message string, code int) {
    w.Header().Set("Content-Type", "application/json; charset=utf-8")
    w.WriteHeader(code)
    fmt.Fprintf(w, "{message: %q}", message)
}

func ResponseWithJSON(w http.ResponseWriter, json []byte, code int) {
    w.Header().Set("Content-Type", "application/json; charset=utf-8")
    w.WriteHeader(code)
    w.Write(json)
}

type Book struct {
    ISBN    string   `json:"isbn"`
    Title   string   `json:"title"`
    Authors []string `json:"authors"`
    Price   string   `json:"price"`
}

func main() {
    session, err := mgo.Dial("mongodb://root:87654321@127.0.0.1:27017/douyin")
    if err != nil {
        panic(err)
    }
    defer session.Close()

    session.SetMode(mgo.Monotonic, true)
    ensureIndex(session)

    mux := goji.NewMux()
    mux.HandleFunc(pat.Post("/books"), addBook(session))
    http.ListenAndServe("192.168.8.200:8888", mux)
}

func ensureIndex(s *mgo.Session) {
    session := s.Copy()
    defer session.Close()

    c := session.DB("douyin").C("books")

    index := mgo.Index{
        Key:        []string{"isbn"},
        Unique:     true,
        DropDups:   true,
        Background: true,
        Sparse:     true,
    }
    err := c.EnsureIndex(index)
    if err != nil {
        panic(err)
    }
}

func addBook(s *mgo.Session) func(w http.ResponseWriter, r *http.Request) {
    return func(w http.ResponseWriter, r *http.Request) {
        session := s.Copy()
        defer session.Close()

        var book Book
        decoder := json.NewDecoder(r.Body)
        err := decoder.Decode(&book)
        if err != nil {
            ErrorWithJSON(w, "資料格式不對", http.StatusBadRequest)
            return
        }

        c := session.DB("douyin").C("books")

        err = c.Insert(book)
        if err != nil {
            if mgo.IsDup(err) {
                ErrorWithJSON(w, "書的isbn已存在", http.StatusBadRequest)
                return
            }

            ErrorWithJSON(w, "伺服器錯誤", http.StatusInternalServerError)
            log.Println("新增書失敗!!!: ", err)
            return
        }

        w.Header().Set("Content-Type", "application/json")
        w.Header().Set("Location", r.URL.Path+"/"+book.ISBN)
        w.WriteHeader(http.StatusCreated)
    }
}

然後就就執行以上程式,

go run  mongdb-add.go

開啟postman測試

查詢資料庫是否已存在

2.2 查詢單書籍介面

新建go檔案mongdb-select.go,鍵入以下程式碼

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"

    "goji.io"
    "goji.io/pat"
    "gopkg.in/mgo.v2"
    "gopkg.in/mgo.v2/bson"
)

func ErrorWithJSON(w http.ResponseWriter, message string, code int) {
    w.Header().Set("Content-Type", "application/json; charset=utf-8")
    w.WriteHeader(code)
    fmt.Fprintf(w, "{message: %q}", message)
}

func ResponseWithJSON(w http.ResponseWriter, json []byte, code int) {
    w.Header().Set("Content-Type", "application/json; charset=utf-8")
    w.WriteHeader(code)
    w.Write(json)
}

type Book struct {
    ISBN    string   `json:"isbn"`
    Title   string   `json:"title"`
    Authors []string `json:"authors"`
    Price   string   `json:"price"`
}

func main() {
    session, err := mgo.Dial("mongodb://root:87654321@127.0.0.1:27017/douyin")
    if err != nil {
        panic(err)
    }
    defer session.Close()

    session.SetMode(mgo.Monotonic, true)
    ensureIndex(session)

    mux := goji.NewMux()
    mux.HandleFunc(pat.Get("/books/:isbn"), bookByISBN(session))     
    http.ListenAndServe("192.168.8.200:8888", mux)
}

func ensureIndex(s *mgo.Session) {
    session := s.Copy()
    defer session.Close()

    c := session.DB("douyin").C("books")

    index := mgo.Index{
        Key:        []string{"isbn"},
        Unique:     true,
        DropDups:   true,
        Background: true,
        Sparse:     true,
    }
    err := c.EnsureIndex(index)
    if err != nil {
        panic(err)
    }
}

func bookByISBN(s *mgo.Session) func(w http.ResponseWriter, r *http.Request) {
    return func(w http.ResponseWriter, r *http.Request) {
        session := s.Copy()
        defer session.Close()

        isbn := pat.Param(r, "isbn")

        c := session.DB("store").C("books")

        var book Book
        err := c.Find(bson.M{"isbn": isbn}).One(&book)
        if err != nil {
            ErrorWithJSON(w, "資料庫錯誤", http.StatusInternalServerError)
            log.Println("查詢isbn的書失敗: ", err)
            return
        }

        if book.ISBN == "" {
            ErrorWithJSON(w, "書不存在", http.StatusNotFound)
            return
        }

        respBody, err := json.MarshalIndent(book, "", "  ")
        if err != nil {
            log.Fatal(err)
        }

        ResponseWithJSON(w, respBody, http.StatusOK)
    }
}

執行程式

go run  mongdb-select.go

繼續用postman測試介面

2.3 修改單書籍介面

新建go檔案mongdb-update.go,鍵入以下程式碼

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"

    "goji.io"
    "goji.io/pat"
    "gopkg.in/mgo.v2"
    "gopkg.in/mgo.v2/bson"
)

func ErrorWithJSON(w http.ResponseWriter, message string, code int) {
    w.Header().Set("Content-Type", "application/json; charset=utf-8")
    w.WriteHeader(code)
    fmt.Fprintf(w, "{message: %q}", message)
}

func ResponseWithJSON(w http.ResponseWriter, json []byte, code int) {
    w.Header().Set("Content-Type", "application/json; charset=utf-8")
    w.WriteHeader(code)
    w.Write(json)
}

type Book struct {
    ISBN    string   `json:"isbn"`
    Title   string   `json:"title"`
    Authors []string `json:"authors"`
    Price   string   `json:"price"`
}

func main() {
    session, err := mgo.Dial("mongodb://root:87654321@127.0.0.1:27017/douyin")
    if err != nil {
        panic(err)
    }
    defer session.Close()

    session.SetMode(mgo.Monotonic, true)
    ensureIndex(session)

    mux := goji.NewMux()
    mux.HandleFunc(pat.Put("/books/:isbn"), updateBook(session))     
    http.ListenAndServe("192.168.8.200:8888", mux)
}

func ensureIndex(s *mgo.Session) {
    session := s.Copy()
    defer session.Close()

    c := session.DB("douyin").C("books")

    index := mgo.Index{
        Key:        []string{"isbn"},
        Unique:     true,
        DropDups:   true,
        Background: true,
        Sparse:     true,
    }
    err := c.EnsureIndex(index)
    if err != nil {
        panic(err)
    }
}

func updateBook(s *mgo.Session) func(w http.ResponseWriter, r *http.Request) {
    return func(w http.ResponseWriter, r *http.Request) {
        session := s.Copy()
        defer session.Close()

        isbn := pat.Param(r, "isbn")

        var book Book
        decoder := json.NewDecoder(r.Body)
        err := decoder.Decode(&book)
        if err != nil {
            ErrorWithJSON(w, "Incorrect body", http.StatusBadRequest)
            return
        }

        c := session.DB("douyin").C("books")

        err = c.Update(bson.M{"isbn": isbn}, &book)
        if err != nil {
            switch err {
            default:
                ErrorWithJSON(w, "Database error", http.StatusInternalServerError)
                log.Println("Failed update book: ", err)
                return
            case mgo.ErrNotFound:
                ErrorWithJSON(w, "Book not found", http.StatusNotFound)
                return
            }
        }

        w.WriteHeader(http.StatusNoContent)
    }
}

執行以上程式

go run  mongdb-update.go

postman繼續測試

再此查詢isbn為1234567890的資訊

2.4 查詢所有書籍介面

新建go檔案mongdb-all.go,鍵入以下程式碼

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"

    "goji.io"
    "goji.io/pat"
    "gopkg.in/mgo.v2"
         "gopkg.in/mgo.v2/bson"
)

func ErrorWithJSON(w http.ResponseWriter, message string, code int) {
    w.Header().Set("Content-Type", "application/json; charset=utf-8")
    w.WriteHeader(code)
    fmt.Fprintf(w, "{message: %q}", message)
}

func ResponseWithJSON(w http.ResponseWriter, json []byte, code int) {
    w.Header().Set("Content-Type", "application/json; charset=utf-8")
    w.WriteHeader(code)
    w.Write(json)
}

type Book struct {
    ISBN    string   `json:"isbn"`
    Title   string   `json:"title"`
    Authors []string `json:"authors"`
    Price   string   `json:"price"`
}

func main() {
    session, err := mgo.Dial("mongodb://root:87654321@127.0.0.1:27017/douyin")
    if err != nil {
        panic(err)
    }
    defer session.Close()

    session.SetMode(mgo.Monotonic, true)
    ensureIndex(session)

    mux := goji.NewMux()
        mux.HandleFunc(pat.Get("/books"), allBooks(session))

    http.ListenAndServe("192.168.8.200:8889", mux)
}

func ensureIndex(s *mgo.Session) {
    session := s.Copy()
    defer session.Close()

    c := session.DB("douyin").C("books")

    index := mgo.Index{
        Key:        []string{"isbn"},
        Unique:     true,
        DropDups:   true,
        Background: true,
        Sparse:     true,
    }
    err := c.EnsureIndex(index)
    if err != nil {
        panic(err)
    }
}

func allBooks(s *mgo.Session) func(w http.ResponseWriter, r *http.Request) {
    return func(w http.ResponseWriter, r *http.Request) {
        session := s.Copy()
        defer session.Close()

        c := session.DB("douyin").C("books")

        var books []Book
        err := c.Find(bson.M{}).All(&books)
        if err != nil {
            ErrorWithJSON(w, "Database error", http.StatusInternalServerError)
            log.Println("Failed get all books: ", err)
            return
        }

        respBody, err := json.MarshalIndent(books, "", "  ")
        if err != nil {
            log.Fatal(err)
        }

        ResponseWithJSON(w, respBody, http.StatusOK)
    }
}

執行該程式

go run  mongdb-all.go

開啟postman或瀏覽器

2.5 刪除單書籍介面

新建go檔案mongdb-delete.go(根據isbn編號),鍵入以下程式碼

package main

import (
    "fmt"
    "log"
    "net/http"

    "goji.io"
    "goji.io/pat"
    "gopkg.in/mgo.v2"
         "gopkg.in/mgo.v2/bson"
)

func ErrorWithJSON(w http.ResponseWriter, message string, code int) {
    w.Header().Set("Content-Type", "application/json; charset=utf-8")
    w.WriteHeader(code)
    fmt.Fprintf(w, "{message: %q}", message)
}

func ResponseWithJSON(w http.ResponseWriter, json []byte, code int) {
    w.Header().Set("Content-Type", "application/json; charset=utf-8")
    w.WriteHeader(code)
    w.Write(json)
}

type Book struct {
    ISBN    string   `json:"isbn"`
    Title   string   `json:"title"`
    Authors []string `json:"authors"`
    Price   string   `json:"price"`
}

func main() {
    session, err := mgo.Dial("mongodb://root:87654321@127.0.0.1:27017/douyin")
    if err != nil {
        panic(err)
    }
    defer session.Close()

    session.SetMode(mgo.Monotonic, true)
    ensureIndex(session)

    mux := goji.NewMux()
        mux.HandleFunc(pat.Delete("/books/:isbn"), deleteBook(session))

    http.ListenAndServe("192.168.8.200:8889", mux)
}

func ensureIndex(s *mgo.Session) {
    session := s.Copy()
    defer session.Close()

    c := session.DB("douyin").C("books")

    index := mgo.Index{
        Key:        []string{"isbn"},
        Unique:     true,
        DropDups:   true,
        Background: true,
        Sparse:     true,
    }
    err := c.EnsureIndex(index)
    if err != nil {
        panic(err)
    }
}
func deleteBook(s *mgo.Session) func(w http.ResponseWriter, r *http.Request) {
    return func(w http.ResponseWriter, r *http.Request) {
        session := s.Copy()
        defer session.Close()

        isbn := pat.Param(r, "isbn")

        c := session.DB("douyin").C("books")

        err := c.Remove(bson.M{"isbn": isbn})
        if err != nil {
            switch err {
            default:
                ErrorWithJSON(w, "Database error", http.StatusInternalServerError)
                log.Println("Failed delete book: ", err)
                return
            case mgo.ErrNotFound:
                ErrorWithJSON(w, "Book not found", http.StatusNotFound)
                return
            }
        }

        w.WriteHeader(http.StatusNoContent)
    }
}

執行以上程式

go run  mongdb-delete.go

用postman測試刪除

然後去資料庫檢視是否還有該isbn為1234567890的書籍

最後加上一點,mongodb和其他資料庫mysql、postgresql一樣面臨資料多需要分頁的情況,類比2012年做的車輛GPS+3G視訊監控排程系統(每輛車只要一啟動開火,就會產生大量的視訊資料,一執行,就會產生很多的gps資料上傳到資料中心,可以通過系統實時檢視車上的視訊情況和執行軌跡),被央視廣泛宣傳推廣。資料量不是一般的多!!!視訊資料還好,一會月沒有盜竊案件事件就刪除了(那時沒有大資料的理念,也沒有用人工智慧訓練資料的初衷,並沒有存下來,且儲存和記憶體還是很貴的,不像現在伺服器幾十上百G記憶體、儲存空間以T為單位),可每輛車每天的gps資料卻是長久儲存的,要是哪天想回看在地圖上的歷史軌跡,就要從很多資料裡檢索,有點像後來衍生出的ofo、摩拜、滴滴和其他共享車平臺。

附程式碼已上傳github: github.com/dongguangming/golang-le...

  1. How To Build Microservice With MongoDB In Golang goinbigdata.com/how-to-build-micro...

本作品採用《CC 協議》,轉載必須註明作者和本文連結

人生,不應設限

相關文章