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)
การติดตั้ง
หากต้องการดาวน์โหลดการพึ่งพา ใช้งานที่อยู่ด้านล่าง
$ go get go.mongodb.org/mongo-driver/mongoการเชื่อมต่อ
ด้านล่างนี้เป็นตัวอย่างการเชื่อมต่อระหว่างไคลเอนต์ mongo กับเซิร์ฟเวอร์
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
// การแสดงเอกสาร BSON แบบมีลำดับ
type D = primitive.D
// คู่คีย์ค่า หน่วยพื้นฐานของการแสดงเอกสาร BSON แบบมีลำดับ
type E = primitive.E
// การแสดงเอกสาร BSON แบบไม่มีลำดับ
type M = primitive.M
// การแสดงข้อมูล BSON แบบมีลำดับ
type A = primitive.Aประเภทจริงของพวกมันมีดังนี้
// การแสดงเอกสาร 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)
ก่อนอื่นสร้างฐานข้อมูล user แทรกข้อมูลต่อไปนี้ลงในคอลเลกชัน users
> use user
> db.users.insertMany([
{
name: "mike",
age: 12,
},
{
name: "jenny",
age: 14,
},
{
name: "jack",
age: 18,
address: "usa"
}
])การค้นหาเดียว
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)โค้ดการค้นหาข้างต้นเทียบเท่ากับ
db.users.findOne({
address: "usa"
})ผลลัพธ์
{Name:jack Age:18 Address:usa}การค้นหาหลายรายการ
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)เทียบเท่ากับ
db.users.find({})ผลลัพธ์
[{Name:jack Age:18 Address:usa} {Name:mike Age:12 Address:} {Name:jenny Age:14 Address:}]เมื่อสร้างเงื่อนไขการค้นหา สามารถใช้ options ได้
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)
ด้านล่างนี้เป็นตัวอย่างการสร้างเอกสารเดียว
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")ด้านล่างนี้เป็นตัวอย่างการสร้างหลายเอกสาร
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
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)เทียบเท่ากับ
db.users.updateOne({
name: "lili"
}, {
$set: {
name: "mark"
},
})ผลลัพธ์
&{MatchedCount:1 ModifiedCount:1 UpsertedCount:0 UpsertedID:<nil>}ด้านล่างนี้เป็นตัวอย่างการอัปเดตหลายเอกสาร อัปเดตที่อยู่ของคนที่มีอายุ 10 ปีเป็น cn
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 ความแตกต่างระหว่างทั้งสองคือ前者อัปเดตฟิลด์เอกสาร后者แทนที่เอกสารโดยตรง เช่น โค้ดด้านล่าง ไม่จำเป็นต้องใช้ตัวดำเนินการอีกต่อไป
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 เพื่อดึงเอกสารและอัปเดตเอกสาร ดังนี้
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)
ด้านล่างนี้เป็นตัวอย่างการลบเอกสารเดียว
result, err := client.Database("user").Collection("users").DeleteOne(ctx, bson.D{
{"name", "jack"},
})
if err != nil {
log.Panicln(err)
}
fmt.Println(result.DeletedCount)ด้านล่างนี้เป็นตัวอย่างการลบหลายเอกสาร
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
type Pipeline []bson.Dpipline := 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 แล้วเรียงลำดับตามอายุ
