大家应该掌握了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("🎉 演示完成")
}