Skip to content

MongoDB

MongoDB เป็นฐานข้อมูลเอกสาร หน่วยข้อมูลพื้นฐานคือเอกสาร รูปแบบการเก็บคือ BSON (Binary JSON) โครงสร้างที่คล้าย JSON โครงสร้างที่ยืดหยุ่นสามารถเก็บข้อมูลประเภทต่างๆ ได้ ทำให้มีความยืดหยุ่นมากกว่าฐานข้อมูลเชิงสัมพันธ์ และใช้ js เป็นภาษาสคริปต์ สามารถดำเนินการแบบผสมผ่านสคริปต์ บทความนี้แนะนำการใช้ไดรเวอร์ mongo ทางการเพื่อดำเนินการกับฐานข้อมูล mongodb ใน Go ไม่ใช่บทเรียน mongodb หากคุณไม่มีพื้นฐาน mongo โปรดศึกษาและเรียนรู้ด้วยตนเองก่อน

เอกสาร mongodb: Introduction to MongoDB — MongoDB Manual

ไดรเวอร์

ไลบรารีของ mongodb ในด้าน go มีค่อนข้างน้อย ในช่วงแรกมีไลบรารีที่ชุมชนดูแล แต่ภายหลังหยุดดูแลแล้ว อย่างไรก็ตาม ไดรเวอร์ mongo ทางการเพียงพอต่อการใช้งาน

ที่เก็บโอเพนซอร์ส: mongodb/mongo-go-driver: The Official Golang driver for MongoDB (github.com)

ที่อยู่เอกสาร: mongodb/mongo-go-driver: The Official Golang driver for MongoDB (github.com)

การติดตั้ง

หากต้องการดาวน์โหลดการพึ่งพา ใช้งานที่อยู่ด้านล่าง

sh
$ go get go.mongodb.org/mongo-driver/mongo

การเชื่อมต่อ

ด้านล่างนี้เป็นตัวอย่างการเชื่อมต่อระหว่างไคลเอนต์ mongo กับเซิร์ฟเวอร์

go
package main

import (
   "context"
   "fmt"
   "go.mongodb.org/mongo-driver/mongo"
   "go.mongodb.org/mongo-driver/mongo/options"
   "go.mongodb.org/mongo-driver/mongo/readpref"
   "log"
)

func main() {
   ctx := context.Background()
   // สร้างการเชื่อมต่อโดยใช้ URI
   client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://admin:123456@192.168.48.138:27017/"))
   if err != nil {
      log.Panicln(err)
   }
   // ปิดการเชื่อมต่อ
   defer client.Disconnect(ctx)
   // ทดสอบ ping เพื่อตรวจสอบว่าการเชื่อมต่อใช้งานได้หรือไม่
   fmt.Println(client.Ping(ctx, readpref.Primary()))
}

bson

mongodb ใน go ใช้ประเภทต่อไปนี้เพื่อแมปเอกสารในฐานข้อมูล อยู่ใน bson/bson.go

go
// การแสดงเอกสาร BSON แบบมีลำดับ
type D = primitive.D

// คู่คีย์ค่า หน่วยพื้นฐานของการแสดงเอกสาร BSON แบบมีลำดับ
type E = primitive.E

// การแสดงเอกสาร BSON แบบไม่มีลำดับ
type M = primitive.M

// การแสดงข้อมูล BSON แบบมีลำดับ
type A = primitive.A

ประเภทจริงของพวกมันมีดังนี้

go
// การแสดงเอกสาร BSON แบบมีลำดับ
type D []E

// คู่คีย์ค่า หน่วยพื้นฐานของการแสดงเอกสาร BSON แบบมีลำดับ
type E struct {
  Key   string
  Value interface{}
}

// การแสดงเอกสาร BSON แบบไม่มีลำดับ
type M map[string]interface{}

// การแสดงข้อมูล BSON แบบมีลำดับ
type A []interface{}

ผ่านประเภทข้างต้น สามารถสร้างคำถาม SQL หรือใช้เพื่อแมปข้อมูล

TIP

ไดเรกทอรี examples ของไดรเวอร์มีตัวอย่างการใช้งานจำนวนมาก ทางการได้สาธิตวิธีการใช้สี่ประเภทข้างต้นอย่างละเอียด

ที่อยู่: mongo-go-driver/examples/documentation_examples/examples.go at master · mongodb/mongo-go-driver (github.com)

การค้นหาเอกสาร

ตัวอย่างการค้นหาทางการ: mongo-go-driver/examples/documentation_examples/examples.go at master · mongodb/mongo-go-driver (github.com)

ก่อนอื่นสร้างฐานข้อมูล user แทรกข้อมูลต่อไปนี้ลงในคอลเลกชัน users

sql
> use user
> db.users.insertMany([
    {
        name: "mike",
        age: 12,

    },
    {
        name: "jenny",
        age: 14,

    },
    {
        name: "jack",
        age: 18,
        address: "usa"
    }
])

การค้นหาเดียว

go
type User struct {
    Name    string `bson:"name"`
    Age     int    `bson:"age"`
    Address string `bson:"address"`
}

var user User

result := client.Database("user"). // เลือกฐานข้อมูล
                    Collection("users").                     // เลือกคอลเลกชัน
                    FindOne(ctx, bson.D{{"address", "usa"}}) // เงื่อนไขการกรอง

// ถอดรหัส
if err := result.Decode(&user); err != nil {
    log.Panicln(err)
}

fmt.Printf("%+v\n", user)

โค้ดการค้นหาข้างต้นเทียบเท่ากับ

sql
db.users.findOne({
    address: "usa"
})

ผลลัพธ์

{Name:jack Age:18 Address:usa}

การค้นหาหลายรายการ

go
type User struct {
   Name    string `bson:"name"`
   Age     int    `bson:"age"`
   Address string `bson:"address"`
}

var users []User

cursor, err := client.Database("user"). // เลือกฐานข้อมูล
               Collection("users"). // เลือกคอลเลกชัน
               Find(ctx, bson.D{})  // เงื่อนไขการกรอง

if err != nil {
   log.Panicln(err)
}

if err := cursor.All(ctx, &users); err != nil {
   log.Panicln(err)
}

fmt.Printf("%+v\n", users)

เทียบเท่ากับ

sql
db.users.find({})

ผลลัพธ์

[{Name:jack Age:18 Address:usa} {Name:mike Age:12 Address:} {Name:jenny Age:14 Address:}]

เมื่อสร้างเงื่อนไขการค้นหา สามารถใช้ options ได้

go
type User struct {
    Name    string `bson:"name"`
    Age     int    `bson:"age"`
    Address string `bson:"address"`
}

var users []User

find := options.Find()
find.SetSort(bson.M{"age": 1})
find.SetLimit(1)

cursor, err := client.Database("user"). // เลือกฐานข้อมูล
                    Collection("users").      // เลือกคอลเลกชัน
                    Find(ctx, bson.D{}, find) // เงื่อนไขการกรอง

if err != nil {
    log.Panicln(err)
}

if err := cursor.All(ctx, &users); err != nil {
    log.Panicln(err)
}

fmt.Printf("%+v\n", users)

เทียบเท่ากับ

db.users.find({}).sort({age:1}).limit(1)

ผลลัพธ์

[{Name:mike Age:12 Address:}]

การสร้างเอกสาร

ตัวอย่างการสร้างทางการ: mongo-go-driver/examples/documentation_examples/examples.go at master · mongodb/mongo-go-driver (github.com)

ด้านล่างนี้เป็นตัวอย่างการสร้างเอกสารเดียว

go
one, err := client.Database("user").Collection("users").InsertOne(ctx, User{
    Name:    "lili",
    Age:     20,
    Address: "china",
})
if err != nil {
    log.Panicln(err)
}
fmt.Println(one.InsertedID)

หลังจากสร้างสำเร็จจะส่งคืน ObjectID ของเอกสาร

ObjectID("64c60fa01e2548d9e4de6cf4")

ด้านล่างนี้เป็นตัวอย่างการสร้างหลายเอกสาร

go
users := []any{User{
    Name:    "john",
    Age:     10,
    Address: "usa",
}, User{
    Name:    "pop",
    Age:     30,
    Address: "uk",
}}

one, err := client.Database("user").Collection("users").InsertMany(ctx, users)
if err != nil {
    log.Panicln(err)
}
fmt.Println(one.InsertedIDs)

หลังจากสร้างสำเร็จจะส่งคืนกลุ่ม ObjectID

[ObjectID("64c610d5aec2618d6ca0b515") ObjectID("64c610d5aec2618d6ca0b516")]

โค้ดสองส่วนข้างต้นเทียบเท่ากับ db.users.insertOne และ db.users.insertMany

การอัปเดตเอกสาร

ตัวอย่างการอัปเดตทางการ: mongo-go-driver/examples/documentation_examples/examples.go at master · mongodb/mongo-go-driver (github.com)

ด้านล่างนี้เป็นตัวอย่างการอัปเดตเอกสารเดียว เปลี่ยนชื่อคนชื่อ lili เป็น mark

go
upres, err := client.Database("user").Collection("users").UpdateOne(ctx, bson.D{
    {"name", "mark"},
},
    bson.D{
       {"$set", bson.D{
          {"name", "lili"},
       }},
    })
if err != nil {
    log.Panicln(err)
}
fmt.Printf("%+v", upres)

เทียบเท่ากับ

sql
db.users.updateOne({
    name: "lili"
}, {
    $set: {
        name: "mark"
    },
})

ผลลัพธ์

&{MatchedCount:1 ModifiedCount:1 UpsertedCount:0 UpsertedID:<nil>}

ด้านล่างนี้เป็นตัวอย่างการอัปเดตหลายเอกสาร อัปเดตที่อยู่ของคนที่มีอายุ 10 ปีเป็น cn

go
upres, err := client.Database("user").Collection("users").UpdateMany(ctx, bson.D{
    {"age", 10},
},
    bson.D{
        {"$set", bson.D{
            {"address", "cn"},
        }},
    })
if err != nil {
    log.Panicln(err)
}
fmt.Printf("%+v", upres)

นอกจากใช้ Update แล้ว mongo ยังจัดเตรียม Replace ความแตกต่างระหว่างทั้งสองคือ前者อัปเดตฟิลด์เอกสาร后者แทนที่เอกสารโดยตรง เช่น โค้ดด้านล่าง ไม่จำเป็นต้องใช้ตัวดำเนินการอีกต่อไป

go
upres, err := client.Database("user").Collection("users").ReplaceOne(ctx, bson.D{
    {"age", 10},
},
    bson.D{
       {"address", "cn"},
    })
if err != nil {
    log.Panicln(err)
}
fmt.Printf("%+v", upres)

ในขณะเดียวกัน mongo ยังจัดเตรียม FindOneAndUpdate และ FindOneAndReplace เพื่อดึงเอกสารและอัปเดตเอกสาร ดังนี้

go
res := client.Database("user").Collection("users").FindOneAndReplace(ctx, bson.D{
    {"address", "cn"},
},
    bson.D{
       {"address", "uk"},
    })
if err := res.Err(); err != nil {
    log.Panicln(err)
}

var user User

res.Decode(&user)

fmt.Printf("%+v", user)

ผลลัพธ์

Name: Age:0 Address:cn}

การดำเนินการนี้จะค้นหาเอกสารก่อนแล้วจึงแก้ไขเอกสาร

การลบเอกสาร

ตัวอย่างการลบทางการ: mongo-go-driver/examples/documentation_examples/examples.go at master · mongodb/mongo-go-driver (github.com)

ด้านล่างนี้เป็นตัวอย่างการลบเอกสารเดียว

go
result, err := client.Database("user").Collection("users").DeleteOne(ctx, bson.D{
    {"name", "jack"},
})
if err != nil {
    log.Panicln(err)
}
fmt.Println(result.DeletedCount)

ด้านล่างนี้เป็นตัวอย่างการลบหลายเอกสาร

go
result, err := client.Database("user").Collection("users").DeleteMany(ctx, bson.D{
    {"age", "10"},
})
if err != nil {
    log.Panicln(err)
}
fmt.Println(result.DeletedCount)

การรวม

ตัวอย่างการรวมทางการ: mongo-go-driver/examples/documentation_examples/examples.go at master · mongodb/mongo-go-driver (github.com)

การดำเนินการรวมใช้ประเภท mongo.Pipeline ซึ่งโดยพื้นฐานแล้วคือ []bson.D

go
type Pipeline []bson.D
go
pipline := mongo.Pipeline{
    {
       {"$match", bson.D{
          {"address", "uk"},
       }},
    },
    {
       {"$sort", bson.D{
          {"age", 1},
       }},
    },
}
aggregate, err := client.Database("user").Collection("users").Aggregate(ctx, pipline)
if err != nil {
    log.Panicln(err)
}
var users []User
if err := aggregate.All(ctx, &users); err != nil {
    log.Panicln(err)
}
log.Println(users)

ผลลัพธ์

[{lili 20 uk} {kak 30 uk}]

การดำเนินการรวมนี้คือการจับคู่ผู้ใช้ทั้งหมดที่มี address เป็น uk แล้วเรียงลำดับตามอายุ

Golang by www.golangdev.cn edit