go代码操作mongodb

miloyang
0 评论
/ /
34 阅读
/
7450 字
13 2025-08

大家应该掌握了mongodb的初始化知识,来实践一些。我封装了一些库。

需求

有一个学生管理的需求,包含了学生的id、名称、性别、年龄、班级等等,需要存在mongodb里面,有增删改查的需求。

代码封装

首先需要准备库,用的是mongo和bson。

go get go.mongodb.org/mongo-driver/mongo@v1.16.0
go get go.mongodb.org/mongo-driver/bson@v1.16.0

数据模型为:

type Student struct {
    ID        primitive.ObjectID `bson:"_id,omitempty"` // Mongo内部ID
    StudentID string             `bson:"student_id"`    // 学号(唯一)
    Name      string             `bson:"name"`          // 姓名
    Gender    string             `bson:"gender"`        // 性别:male/female
    Age       int                `bson:"age"`           // 年龄
    Class     string             `bson:"class"`         // 班级
    CreatedAt time.Time          `bson:"created_at"`
    UpdatedAt time.Time          `bson:"updated_at"`
}

数据库初始化

type Store struct {
    Client     *mongo.Client
    DB         *mongo.Database
    Collection *mongo.Collection
}

func connect() (*Store, error) {
    dbName := "school"
    uri := "mongodb://ip:port/school"
    clientOpts := options.Client().ApplyURI(uri)
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    client, err := mongo.Connect(ctx, clientOpts)
    if err != nil {
        return nil, err
    }
    // Ping确保连通
    if err := client.Ping(ctx, nil); err != nil {
        return nil, err
    }
    db := client.Database(dbName)
    col := db.Collection("students")
    return &Store{Client: client, DB: db, Collection: col}, nil
}

// 创建唯一索引:student_id
func (s *Store) ensureIndexes(ctx context.Context) error {
    model := mongo.IndexModel{
        Keys:    bson.D{{Key: "student_id", Value: 1}},
        Options: options.Index().SetUnique(true).SetName("uniq_student_id"),
    }
    _, err := s.Collection.Indexes().CreateOne(ctx, model)
    return err
}

创建学生

func (s *Store) CreateStudent(ctx context.Context, st Student) (primitive.ObjectID, error) {
    now := time.Now()
    st.CreatedAt = now
    st.UpdatedAt = now
    res, err := s.Collection.InsertOne(ctx, st)
    if err != nil {
        return primitive.NilObjectID, err
    }
    id, _ := res.InsertedID.(primitive.ObjectID)
    return id, nil
}

批量更新学生

使用upsert,这样写入时更安全、可幂等。

func (s *Store) UpsertStudentsByStudentID(ctx context.Context, items []Student) error {
    var models []mongo.WriteModel
    now := time.Now()
    for _, it := range items {
        it.UpdatedAt = now
        if it.CreatedAt.IsZero() {
            it.CreatedAt = now
        }
        filter := bson.M{"student_id": it.StudentID}
        update := bson.M{"$set": it}
        models = append(models, mongo.NewUpdateOneModel().
            SetFilter(filter).
            SetUpdate(update).
            SetUpsert(true))
    }
    _, err := s.Collection.BulkWrite(ctx, models, options.BulkWrite().SetOrdered(false))
    return err
}

查询单个的学生

func (s *Store) GetStudentByStudentID(ctx context.Context, studentID string) (*Student, error) {
    var st Student
    err := s.Collection.FindOne(ctx, bson.M{"student_id": studentID}).Decode(&st)
    if err == mongo.ErrNoDocuments {
        return nil, nil
    }
    return &st, err
}

分页查询

// ListStudents 按条件分页查询(简单演示:可加 skip/limit、排序)
func (s *Store) ListStudents(ctx context.Context, class string, minAge, maxAge int) ([]Student, error) {
    filter := bson.M{}
    if class != "" {
        filter["class"] = class
    }
    if minAge > 0 || maxAge > 0 {
        ageCond := bson.M{}
        if minAge > 0 {
            ageCond["$gte"] = minAge
        }
        if maxAge > 0 {
            ageCond["$lte"] = maxAge
        }
        filter["age"] = ageCond
    }
    opts := options.Find().SetSort(bson.D{{Key: "student_id", Value: 1}})

    cur, err := s.Collection.Find(ctx, filter, opts)
    if err != nil {
        return nil, err
    }
    defer cur.Close(ctx)

    var out []Student
    for cur.Next(ctx) {
        var st Student
        if err := cur.Decode(&st); err != nil {
            return nil, err
        }
        out = append(out, st)
    }
    return out, cur.Err()
}

删除

func (s *Store) DeleteStudentByStudentID(ctx context.Context, studentID string) (int64, error) {
    res, err := s.Collection.DeleteOne(ctx, bson.M{"student_id": studentID})
    if err != nil {
        return 0, err
    }
    return res.DeletedCount, nil
}

main调用

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
    defer cancel()

    store, err := connect()
    if err != nil {
        log.Fatalf("connect mongo failed: %v", err)
    }
    defer func() {
        _ = store.Client.Disconnect(context.Background())
    }()

    // 确保唯一索引
    if err := store.ensureIndexes(ctx); err != nil {
        log.Fatalf("ensureIndexes failed: %v", err)
    }
    // 1) Mock数据Upsert(幂等,可重复执行)
    if err := store.UpsertStudentsByStudentID(ctx, mockStudents()); err != nil {
        log.Fatalf("upsert mock data failed: %v", err)
    }
    fmt.Println("✅ Mock 数据写入完成(幂等 Upsert)")

    // 2) 创建一个新学生(演示 InsertOne)
    /*alice := Student{
        StudentID: "S20250010",
        Name:      "Alice",
        Gender:    "female",
        Age:       15,
        Class:     "高一(5)班",
    }
    newID, err := store.CreateStudent(ctx, alice)
    if err != nil {
        log.Fatalf("create student failed: %v", err)
    }
    fmt.Printf("✅ 新增学生:student_id=%s, _id=%s\n", alice.StudentID, newID.Hex())
    */
    // 3) 查询单个学生
    st, err := store.GetStudentByStudentID(ctx, "S20250002")
    if err != nil {
        log.Fatalf("get student failed: %v", err)
    }
    if st != nil {
        fmt.Printf("🔎 查询到 S20250002:%+v\n", *st)
    } else {
        fmt.Println("🔎 未找到 S20250002")
    }

    // 4) 列表查询(班级=高三(1)班,年龄15~20)
    list, err := store.ListStudents(ctx, "高三(1)班", 15, 20)
    if err != nil {
        log.Fatalf("list students failed: %v", err)
    }
    fmt.Printf("📃 列表查询(高三1班, 15~20岁) 共 %d 人\n", len(list))
    for _, it := range list {
        fmt.Printf(" - %s %s %d岁 %s\n", it.StudentID, it.Name, it.Age, it.Class)
    }
    // 5) 更新(把 S20250001 的年龄更新为 19)
    modified, err := store.UpdateStudentByStudentID(ctx, "S20250001", bson.M{"age": 19})
    if err != nil {
        log.Fatalf("update student failed: %v", err)
    }
    fmt.Printf("✏️  更新 S20250001,修改记录数:%d\n", modified)
    // 6) 删除(删除 S20250010)
    deleted, err := store.DeleteStudentByStudentID(ctx, "S20250010")
    if err != nil {
        log.Fatalf("delete student failed: %v", err)
    }
    fmt.Printf("🗑️  删除 S20250010,删除记录数:%d\n", deleted)

    fmt.Println("🎉 演示完成")
}
人未眠
工作数十年
脚步未曾歇,学习未曾停
乍回首
路程虽丰富,知识未记录
   借此博客,与之共进步