Skip to content

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.

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

Kế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ủ.

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()
   // 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

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.A

Các loại thực tế của chúng như sau

go
// 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.

Địa chỉ: mongo-go-driver/examples/documentation_examples/examples.go at master · mongodb/mongo-go-driver (github.com)

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

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

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

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

Truy vấn đơn

go
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

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

Kết quả đầu ra

{Name:jack Age:18 Address:usa}

Truy vấn nhiều

go
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

sql
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

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"). // 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

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)

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

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)

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.insertOnedb.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

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)

Tương đương với

sql
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

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)

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.

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)

Đồng thời mongo còn cung cấp FindOneAndUpdateFindOneAndReplace để lấy tài liệu và cập nhật tài liệu. Như sau

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)

Đầ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

go
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

go
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

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)

Đầ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.

Golang by www.golangdev.cn edit