MongoDB
MongoDB là một cơ sở dữ liệu tài liệu, đơn vị dữ liệu cơ bản là tài liệu, định dạng lưu trữ là BSON (Binary JSON) - một cấu trúc tương tự JSON. Cấu trúc lỏng lẻo này có thể lưu trữ nhiều loại dữ liệu khác nhau, linh hoạt hơn so với cơ sở dữ liệu quan hệ và sử dụng js làm ngôn ngữ kịch bản, cho phép thực hiện các thao tác kết hợp thông qua kịch bản. Bài viết này chủ yếu giới thiệu cách sử dụng trình điều khiển mongo chính thức để thao tác cơ sở dữ liệu mongodb trong Go, không phải là hướng dẫn mongodb. Nếu bạn chưa có kiến thức cơ bản về mongo, vui lòng tự tìm hiểu và học trước.
Tài liệu mongodb: Introduction to MongoDB — MongoDB Manual
Trình điều khiển
Thư viện liên quan đến mongo trong Go khá ít, trước đây có một số thư viện do cộng đồng duy trì nhưng sau đó đã ngừng duy trì. Tuy nhiên, trình điều khiển mongo chính thức đã hoàn toàn đủ để sử dụng.
Kho lưu trữ mã nguồn mở: mongodb/mongo-go-driver: The Official Golang driver for MongoDB (github.com)
Địa chỉ tài liệu: mongodb/mongo-go-driver: The Official Golang driver for MongoDB (github.com)
Cài đặt
Để tải xuống phụ thuộc, sử dụng địa chỉ bên dưới.
$ go get go.mongodb.org/mongo-driver/mongoKết nối
Dưới đây là ví dụ đơn giản về việc thiết lập kết nối giữa máy khách mongo và máy chủ.
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()
// Sử dụng URI để thiết lập kết nối
client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://admin:123456@192.168.48.138:27017/"))
if err != nil {
log.Panicln(err)
}
// Đóng kết nối
defer client.Disconnect(ctx)
// Kiểm tra kết nối bằng ping
fmt.Println(client.Ping(ctx, readpref.Primary()))
}bson
Trong mongodb của Go, các loại sau được sử dụng để ánh xạ tài liệu trong cơ sở dữ liệu, nằm trong bson/bson.go
// Biểu diễn có thứ tự của tài liệu BSON
type D = primitive.D
// Một cặp khóa-giá trị, đơn vị cơ bản của biểu diễn có thứ tự tài liệu BSON
type E = primitive.E
// Biểu diễn không có thứ tự của tài liệu BSON
type M = primitive.M
// Biểu diễn có thứ tự của dữ liệu BSON
type A = primitive.ACác loại thực tế của chúng như sau
// Biểu diễn có thứ tự của tài liệu BSON
type D []E
// Một cặp khóa-giá trị, đơn vị cơ bản của biểu diễn có thứ tự tài liệu BSON
type E struct {
Key string
Value interface{}
}
// Biểu diễn không có thứ tự của tài liệu BSON
type M map[string]interface{}
// Biểu diễn có thứ tự của dữ liệu BSON
type A []interface{}Thông qua các loại trên, có thể xây dựng câu lệnh SQL truy vấn hoặc ánh xạ dữ liệu.
TIP
Thư mục examples của trình điều khiển có khá nhiều ví dụ sử dụng,官方 đã trình diễn chi tiết cách sử dụng bốn loại nêu trên.
Truy vấn tài liệu
Ví dụ truy vấn chính thức: mongo-go-driver/examples/documentation_examples/examples.go at master · mongodb/mongo-go-driver (github.com)
Trước tiên tạo cơ sở dữ liệu user, chèn dữ liệu sau vào collection users
> use user
> db.users.insertMany([
{
name: "mike",
age: 12,
},
{
name: "jenny",
age: 14,
},
{
name: "jack",
age: 18,
address: "usa"
}
])Truy vấn đơn
type User struct {
Name string `bson:"name"`
Age int `bson:"age"`
Address string `bson:"address"`
}
var user User
result := client.Database("user"). // Chọn cơ sở dữ liệu
Collection("users"). // Chọn collection
FindOne(ctx, bson.D{{"address", "usa"}}) // Điều kiện lọc
// Giải tuần tự
if err := result.Decode(&user); err != nil {
log.Panicln(err)
}
fmt.Printf("%+v\n", user)Đoạn mã truy vấn trên tương đương với
db.users.findOne({
address: "usa"
})Kết quả đầu ra
{Name:jack Age:18 Address:usa}Truy vấn nhiều
type User struct {
Name string `bson:"name"`
Age int `bson:"age"`
Address string `bson:"address"`
}
var users []User
cursor, err := client.Database("user"). // Chọn cơ sở dữ liệu
Collection("users"). // Chọn collection
Find(ctx, bson.D{}) // Điều kiện lọc
if err != nil {
log.Panicln(err)
}
if err := cursor.All(ctx, &users); err != nil {
log.Panicln(err)
}
fmt.Printf("%+v\n", users)Tương đương với
db.users.find({})Đầu ra
[{Name:jack Age:18 Address:usa} {Name:mike Age:12 Address:} {Name:jenny Age:14 Address:}]Khi xây dựng điều kiện truy vấn, cũng có thể sử dụng 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"). // Chọn cơ sở dữ liệu
Collection("users"). // Chọn collection
Find(ctx, bson.D{}, find) // Điều kiện lọc
if err != nil {
log.Panicln(err)
}
if err := cursor.All(ctx, &users); err != nil {
log.Panicln(err)
}
fmt.Printf("%+v\n", users)Tương đương với
db.users.find({}).sort({age:1}).limit(1)Đầu ra
[{Name:mike Age:12 Address:}]Tạo tài liệu
Ví dụ tạo chính thức: mongo-go-driver/examples/documentation_examples/examples.go at master · mongodb/mongo-go-driver (github.com)
Dưới đây là ví dụ về việc tạo một tài liệu
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)Sau khi tạo thành công sẽ trả về ObjectID của tài liệu
ObjectID("64c60fa01e2548d9e4de6cf4")Dưới đây là ví dụ về việc tạo nhiều tài liệu
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)Sau khi tạo thành công sẽ trả về một nhóm ObjectID
[ObjectID("64c610d5aec2618d6ca0b515") ObjectID("64c610d5aec2618d6ca0b516")]Hai đoạn mã trên tương đương với db.users.insertOne và db.users.insertMany.
Cập nhật tài liệu
Ví dụ cập nhật chính thức: mongo-go-driver/examples/documentation_examples/examples.go at master · mongodb/mongo-go-driver (github.com)
Dưới đây là ví dụ về việc cập nhật một tài liệu đơn, đổi tên người tên lili thành 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)Tương đương với
db.users.updateOne({
name: "lili"
}, {
$set: {
name: "mark"
},
})Đầu ra
&{MatchedCount:1 ModifiedCount:1 UpsertedCount:0 UpsertedID:<nil>}Dưới đây là ví dụ về việc cập nhật nhiều tài liệu, cập nhật địa chỉ của người có tuổi là 10 thành 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)Ngoài việc sử dụng Update, mongo còn cung cấp Replace, sự khác biệt giữa hai cái là cái trước cập nhật trường tài liệu, cái sau thay thế trực tiếp tài liệu. Ví dụ như đoạn mã dưới đây, không cần toán tử nữa.
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)Đồng thời mongo còn cung cấp FindOneAndUpdate và FindOneAndReplace để lấy tài liệu và cập nhật tài liệu. Như sau
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)Đầu ra
Name: Age:0 Address:cn}Thao tác này sẽ truy vấn tài liệu trước rồi sau đó sửa đổi tài liệu.
Xóa tài liệu
Ví dụ xóa chính thức: mongo-go-driver/examples/documentation_examples/examples.go at master · mongodb/mongo-go-driver (github.com)
Dưới đây là ví dụ về việc xóa một tài liệu
result, err := client.Database("user").Collection("users").DeleteOne(ctx, bson.D{
{"name", "jack"},
})
if err != nil {
log.Panicln(err)
}
fmt.Println(result.DeletedCount)Dưới đây là ví dụ về việc xóa nhiều tài liệu
result, err := client.Database("user").Collection("users").DeleteMany(ctx, bson.D{
{"age", "10"},
})
if err != nil {
log.Panicln(err)
}
fmt.Println(result.DeletedCount)Tổng hợp
Ví dụ tổng hợp chính thức: mongo-go-driver/examples/documentation_examples/examples.go at master · mongodb/mongo-go-driver (github.com)
Thao tác tổng hợp sử dụng loại mongo.Pipeline, bản chất của nó là []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)Đầu ra
[{lili 20 uk} {kak 30 uk}]Thao tác tổng hợp này khớp tất cả người dùng có address là uk, sau đó sắp xếp theo tuổi.
