From 13cd706505798ac2c81d969a22b82e3801feac08 Mon Sep 17 00:00:00 2001 From: "suguo.yao" Date: Fri, 15 Dec 2023 13:52:21 +0800 Subject: [PATCH] =?UTF-8?q?mongo=20docker=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mongo2/mongo.go | 109 +++++++++++++++++ mongo2/mongo_test.go | 270 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 379 insertions(+) create mode 100644 mongo2/mongo.go create mode 100644 mongo2/mongo_test.go diff --git a/mongo2/mongo.go b/mongo2/mongo.go new file mode 100644 index 0000000..e4197dc --- /dev/null +++ b/mongo2/mongo.go @@ -0,0 +1,109 @@ +package mongo + +import ( + "context" + "errors" + "os" + "strings" + "time" + + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/mongo/readpref" +) + +var ( + mongo_uri string + mongo_database string + mongo_username string + mongo_password string +) + +func init() { + mongo_uri = os.Getenv("MONGO_URI") + if mongo_uri == "" { + mongo_uri = "mongodb://localhost:27017" + } + mongo_database = os.Getenv("MONGO_DB") + if mongo_database == "" { + mongo_database = "admin" + } + mongo_username = os.Getenv("MONGO_USERNAME") + mongo_password = os.Getenv("MONGO_PASSWORD") +} + +// 新连接获取 +func newConnect() (*mongo.Client, error) { + clientOpts := options.Client().ApplyURI(mongo_uri).SetConnectTimeout(3 * time.Second) + + if mongo_username != "" && mongo_password != "" { + clientOpts = clientOpts.SetAuth(options.Credential{ + AuthMechanism: "SCRAM-SHA-256", + AuthSource: "admin", + Username: mongo_username, + Password: mongo_password, + }) + } + + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + + return mongo.Connect(ctx, clientOpts) +} + +func newDB(client *mongo.Client, dbname string) (*mongo.Database, error) { + db := dbname + if db == "" { + db = mongo_database + } + + return client.Database(db), nil +} + +func newCollection(client *mongo.Client, dbname, colname string) (*mongo.Collection, error) { + db, err := newDB(client, dbname) + if err != nil { + return nil, err + } + return db.Collection(colname), nil +} + +// 获取默认集合,即数据库名已指定的库 +func newDefaultCollection(client *mongo.Client, colname string) (*mongo.Collection, error) { + db, err := newDB(client, "") + if err != nil { + return nil, err + } + return db.Collection(colname), nil +} + +func ping() error { + client, err := newConnect() + if err != nil { + return err + } + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + defer client.Disconnect(ctx) + return client.Ping(ctx, readpref.Primary()) +} + +// Collection 获取集合 +func Collection(client *mongo.Client, cname string) (*mongo.Collection, error) { + collection := client.Database(mongo_database).Collection(cname) + return collection, nil +} + +// CollectionMulti 支持多数据库直接获取collection +func CollectionMulti(client *mongo.Client, cname string) (*mongo.Collection, error) { + name := strings.Split(cname, ".") + if len(name) != 2 { + return nil, errors.New("collection名称不正确,请使用[database.collection]方式使用") + } + if name[0] == "" || name[1] == "" { + return nil, errors.New("名称不能为空") + } + + collection := client.Database(name[0]).Collection(name[1]) + return collection, nil +} diff --git a/mongo2/mongo_test.go b/mongo2/mongo_test.go new file mode 100644 index 0000000..73484ce --- /dev/null +++ b/mongo2/mongo_test.go @@ -0,0 +1,270 @@ +package mongo + +import ( + "context" + "fmt" + "testing" + "time" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +func init() { + mongo_uri = "mongodb://192.168.0.254:27017" + mongo_database = "sample" + mongo_username = "aaa" + mongo_password = "bbb123" +} + +func TestPing(t *testing.T) { + if err := ping(); err != nil { + t.Fatal(err) + } +} + +type Student struct { + ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` //确保在 BSON 编码/解码时,当 _id 为空时不会将其包含在文档中。在插入文档时,可以不设置 ID 字段,MongoDB 驱动会自动为其生成一个唯一的 ObjectID。 + Name string `json:"name,omitempty"` + Sex string `json:"sex,omitempty"` + CourseID int `bson:"courseid,omitempty" json:"course_id,omitempty"` + StudentID int `json:"student_id,omitempty"` +} + +func TestInsert(t *testing.T) { + client, err := newConnect() + if err != nil { + t.Fatal(err) + } + defer client.Disconnect(context.Background()) + + for i := 0; i < 10000; i++ { + collection, err := newCollection(client, "", "student") + if err != nil { + t.Fatal(err) + } + n := fmt.Sprintf("张小凡%d", i) + ret, err := collection.InsertOne(context.Background(), &Student{Name: n, Sex: "女", StudentID: i, CourseID: i % 10}) + if err != nil { + t.Fatal(err) + } + fmt.Println(i, ret) + fmt.Println(ret.InsertedID.(primitive.ObjectID).Hex()) + } +} + +func TestInsertCourse(t *testing.T) { + client, err := newConnect() + if err != nil { + t.Fatal(err) + } + defer client.Disconnect(context.Background()) + + for i := 2; i < 10; i++ { + collection, err := newCollection(client, "", "course") + if err != nil { + t.Fatal(err) + } + n := fmt.Sprintf("sports%d", i) + ret, err := collection.InsertOne(context.Background(), &Course{ID: i, Name: n, Title: "sports"}) + if err != nil { + t.Fatal(err) + } + fmt.Println(i, ret) + } +} + +func TestDelete(t *testing.T) { + client, err := newConnect() + if err != nil { + t.Fatal(err) + } + defer client.Disconnect(context.Background()) + col, err := newCollection(client, "", "student") + if err != nil { + t.Fatal(err) + } + + if err := col.FindOneAndDelete(context.Background(), bson.D{{"name", "张惠"}}).Err(); err != nil { + t.Fatal(err) + } + ret, err := col.DeleteOne(context.Background(), bson.D{{"name", "张惠"}}) + if err != nil { + t.Fatal(err) + } + fmt.Println(ret) + ret, err = col.DeleteMany(context.Background(), bson.D{{"name", "张惠"}}) + if err != nil { + t.Fatal(err) + } + fmt.Println(ret) +} + +func TestSingleResult(t *testing.T) { + client, err := newConnect() + if err != nil { + t.Fatal(err) + } + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + defer client.Disconnect(ctx) + col, err := Collection(client, "student") + if err != nil { + t.Fatal(err) + } + var result Student + // if err := col.FindOne(ctx, bson.D{{"name", "张惠"}}).Decode(&result); err != nil { + if err := col.FindOne(ctx, bson.M{"name": "张惠0"}).Decode(&result); err != nil { + if err != mongo.ErrNoDocuments { + t.Fatal(err) + } + } + fmt.Println(result) +} + +func TestFindAll(t *testing.T) { + client, err := newConnect() + if err != nil { + t.Fatal(err) + } + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + defer client.Disconnect(ctx) + col, err := newCollection(client, "", "student") + if err != nil { + t.Fatal(err) + } + cur, err := col.Find(ctx, bson.D{}) + if err != nil { + t.Fatal(err) + } + defer cur.Close(ctx) + for cur.Next(ctx) { + var result Student + if err := cur.Decode(&result); err != nil { + t.Fatal(err) + } + fmt.Println(result, result.ID.String(), result.ID.Timestamp(), result.ID.Timestamp().Local()) + } + if err := cur.Err(); err != nil { + t.Fatal(err) + } +} + +func TestFind(t *testing.T) { + client, err := newConnect() + if err != nil { + t.Fatal(err) + } + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + defer client.Disconnect(ctx) + col, err := newDefaultCollection(client, "student") + if err != nil { + t.Fatal(err) + } + cur, err := col.Find(ctx, bson.M{"name": "张小凡1"}) //注意这里的格式$ne不相等,$gt大于,$gte大于等于,$in in,$nin no in ,$exists是否包含这个键... + if err != nil { + t.Fatal(err) + } + defer cur.Close(ctx) + for cur.Next(ctx) { + var result Student + if err := cur.Decode(&result); err != nil { + t.Fatal(err) + } + fmt.Println(result, result.ID.String(), result.ID.Timestamp(), result.ID.Timestamp().Local()) + } + if err := cur.Err(); err != nil { + t.Fatal(err) + } +} + +func TestPage(t *testing.T) { + client, err := newConnect() + if err != nil { + t.Fatal(err) + } + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + defer client.Disconnect(ctx) + col, err := newDefaultCollection(client, "student") + if err != nil { + t.Fatal(err) + } + cur, err := col.Find(ctx, bson.M{}, options.Find().SetSkip(1000).SetLimit(1000)) + if err != nil { + t.Fatal(err) + } + defer cur.Close(ctx) + for cur.Next(ctx) { + var result Student + if err := cur.Decode(&result); err != nil { + t.Fatal(err) + } + fmt.Println(result, result.ID.String(), result.ID.Timestamp(), result.ID.Timestamp().Local()) + } + if err := cur.Err(); err != nil { + t.Fatal(err) + } +} + +type Course struct { + ID int `bson:"_id,omitempty" json:"id,omitempty"` + Name string `json:"name,omitempty"` + Title string `json:"title,omitempty"` +} + +// 关连表查询 +func TestAggregate(t *testing.T) { + // 建立 MongoDB 连接 + client, err := newConnect() + if err != nil { + t.Fatal(err) + } + defer client.Disconnect(context.Background()) + + // 选择数据库和集合 + studentsCollection, err := newDefaultCollection(client, "student") + if err != nil { + t.Fatal(err) + } + + // 执行关联查询 + pipeline := bson.A{ + bson.D{ + {"$match", bson.D{ + {"name", "张小凡1"}, + }}, + }, + bson.D{ + {"$lookup", bson.D{ + {"from", "course"}, + {"localField", "courseid"}, + {"foreignField", "_id"}, + {"as", "courses"}, + }}, + }, + } + + // 执行聚合查询,结果OK + cursor, err := studentsCollection.Aggregate(context.Background(), pipeline) + if err != nil { + t.Fatal(err) + } + defer cursor.Close(context.Background()) + + // 解码查询结果 + var result []bson.M + if err := cursor.All(context.Background(), &result); err != nil { + t.Fatal(err) + } + + // 打印查询结果 + fmt.Println("Result:") + for _, doc := range result { + fmt.Println(doc) + } +}