MongoDB:使用Go语言操作Mongodb

连接MongoDB数据库

在Go语言中连接MongoDB,你可以使用官方的MongoDB Go Driver,即mongo-go-driver。这个库提供了丰富的API来与MongoDB数据库进行交互。以下是一个基本的步骤和示例代码,展示如何在Go程序中连接到MongoDB数据库。

步骤 1: 安装 MongoDB Go Driver

首先,你需要安装MongoDB Go Driver。在你的Go项目目录下,通过运行以下命令来安装:

1
2
go get go.mongodb.org/mongo-driver/mongo  
go get go.mongodb.org/mongo-driver/mongo/options

步骤 2: 编写Go代码连接MongoDB

接下来,你可以编写Go代码来连接到MongoDB数据库。以下是一个简单的示例,展示了如何连接到MongoDB数据库并执行一个基本的查询。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package main  
  
import (  
    "context"  
    "fmt"  
    "log"  
    "time"  
  
    "go.mongodb.org/mongo-driver/bson"  
    "go.mongodb.org/mongo-driver/mongo"  
    "go.mongodb.org/mongo-driver/mongo/options"  
)  
  
func main() {  
    // 设置MongoDB连接字符串 
    // 格式通常为:mongodb://username:password@host:port/dbname
    uri := "mongodb://admin:admin@localhost:27017"
	clientOptions := options.Client().ApplyURI(uri)  
  
    // 连接到MongoDB 
    client, err := mongo.Connect(context.TODO(), clientOptions)  
    if err != nil {  
        log.Fatal(err)  
    }  
  
    // 检查连接  
    err = client.Ping(context.TODO(), nil)  
    if err != nil {  
        log.Fatal(err)  
    }  
    fmt.Println("Connected to MongoDB!")  
  
    // 选择数据库和集合  
    collection := client.Database("testdb").Collection("testcol")  
  
    // 插入文档  
    insertResult, err := collection.InsertOne(context.TODO(), bson.D{{"name", "MongoDB"}, {"type", "database"}, {"count", 1}, {"info", bson.D{{"x", 203}, {"y", 102}}}}})  
    if err != nil {  
        log.Fatal(err)  
    }  
    fmt.Println("Inserted a single document: ", insertResult.InsertedID)  
  
    // 查询文档  
    var result bson.M  
    err = collection.FindOne(context.TODO(), bson.D{{"name", "MongoDB"}}).Decode(&result)  
    if err != nil {  
        log.Fatal(err)  
    }  
    fmt.Printf("Found a single document: %+v\n", result)  
  
    // 关闭MongoDB连接  
    err = client.Disconnect(context.TODO())  
    if err != nil {  
        log.Fatal(err)  
    }  
    fmt.Println("Connection to MongoDB closed.")  
}

context.Context参数

在MongoDB Go Driver中,许多操作都接受一个context.Context参数。

可以使用context.Context来管理连接MongoDB的请求生命周期,主要是为了能够控制操作的执行时间,防止长时间运行的操作阻塞程序,同时也能够在需要时取消这些操作。

下面是一个具体的示例,展示如何在与MongoDB交互时使用context.Context

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
func main() {
	// 创建一个新的MongoDB客户端,使用默认的Context
	client, _ := mongo.Connect(context.Background(), options.Client().ApplyURI("mongodb://localhost:27017"))
	// 选择数据库和集合
	collection := client.Database("mydatabase").Collection("users")
	// 创建一个带有时限的Context,用于查询操作
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	// 使用Context发起查询,查找年龄大于30的用户
	filter := bson.M{"age": bson.M{"$gt": 30}}
	cursor, err := collection.Find(ctx, filter)
	if err != nil {
		if ctx.Err() == context.DeadlineExceeded {
			fmt.Println("Query timed out")
		} else {
			log.Fatal(err)
		}
		return
	}
	defer cursor.Close(ctx)
	// 遍历查询结果
	for cursor.Next(ctx) {
		var user map[string]interface{}
		if err := cursor.Decode(&user); err != nil {
			log.Fatal(err)
		}
		fmt.Println(user)
	}
	// 检查是否有错误发生
	if err := cursor.Err(); err != nil {
		log.Fatal(err)
	}
}

关键点解析

  1. 创建Context:使用context.WithTimeout创建一个带有时限的Context,这个Context将在5秒后超时。

  2. 发起MongoDB操作:将创建的限时Context传递给collection.Find方法,这样查询操作将受到超时限制。

  3. 处理超时:如果查询操作超时,ctx.Err()将返回context.DeadlineExceeded错误,可以通过检查这个错误来判断操作是否因超时而被取消。

  4. 取消Context:在查询操作完成后,调用cancel函数来取消Context,释放资源。

bson.D和bson.M

在MongoDB的Go语言驱动(mongo-go-driver)中,bson.Dbson.M是两种用于表示BSON文档的Go类型。BSON(Binary JSON)是MongoDB中用于存储文档的一种二进制格式的JSON变种。这两种类型各有其用途和优势,下面详细说明它们之间的差异和用法。

bson.D

bson.D是一个文档类型,用于表示有序的键值对序列。它是一个[]bson.E的别名,其中bson.E是一个结构体,包含Key(字符串类型,键名)和Valueinterface{}类型,键值)两个字段。bson.D特别适用于那些需要明确控制BSON文档中字段顺序的场景,因为它保留了元素的插入顺序。

示例

1
2
3
4
5
6
7
8
func main() {  
    doc := bson.D{  
        {"name", "John Doe"},  
        {"age", 30},  
        {"isStudent", false},  
    }  
    // ... 后续操作,如插入文档到MongoDB等  
}

bson.M

bson.M是一个映射类型,用于表示无序的键值对集合。它本质上是map[string]interface{}的别名,因此使用起来非常类似于Go中的标准map。由于它是基于map的,所以它不保留元素的插入顺序。bson.M在编写快速原型或当字段顺序不重要时非常有用。

示例

1
2
3
4
5
6
7
8
func main() {  
    doc := bson.M{  
        "name": "Jane Doe",  
        "age":  28,  
        "isStudent": true,  
    }  
    // ... 后续操作,如插入文档到MongoDB等  
}

使用场景差异

  • 当你需要明确控制BSON文档中字段的顺序时,应该使用bson.D。这在某些情况下是必要的,比如MongoDB的某些操作可能会依赖于字段的顺序(尽管这种情况较少)。
  • 当你不需要关心字段顺序,或者只是想快速编写代码时bson.M是一个更自然、更简洁的选择。

查询

数据库名称为test,集合名称为stus,文档的结构为:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
  "_id" : ObjectId("66869ef8abdfde5a12c58d50"),
  "name" : "Alice",
  "age" : 26,
  "gender" : "female",
  "class" : "computer science 1",
  "score" : 85,
  "hobbies" : {
    "cities" : ["beijing", "shanghai", "shenzhen"],
    "sports" : ["basketball", "tennis"]
  }
}

先创建Go语言的映射结构体:

1
2
3
4
5
6
7
8
type Student struct {
    Name   string `bson:"name"`
    Age    int    `bson:"age"`
    Gender string `bson:"gender"`
    Class  string `bson:"class"`
    Score  int    `bson:"score"`
    // 其他字段...
}

然后在main函数中连接数据库:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
func main() {
    client, err := connectMongodb()
    if err != nil {
       panic(err)
    }
    defer func(client *mongo.Client, ctx context.Context) {
       err := client.Disconnect(ctx)
       if err != nil {
          panic(err)
       }
       fmt.Println("Connection to MongoDB closed.")
    }(client, context.TODO())
    fmt.Println("Connected to MongoDB!")
    // 获取集合
    collection := client.Database("test").Collection("stus")
    // 后面示例的代码写在后面
    // ......
}

mongo.Collection.Find 方法是查询文档的主要方式之一。

方法签名

Go 语言中,mongo.Collection.Find 方法的基本签名如下:

1
2
func (coll *Collection) Find(ctx context.Context, filter interface{},
    opts ...*options.FindOptions) (cur *Cursor, err error)

其中:

  • ctx context.Context:上下文对象,用于控制请求的生命周期,例如设置超时或取消请求。
  • filter interface{}:查询过滤器,可以是任何实现了 bson.RawDocument 接口的对象,通常是一个 map[string]interface{} 结构,用于指定查询条件。
  • *options.FindOptions :一个可选的参数,用于指定查询的附加选项,如排序、限制结果数量、跳过某些结果等。

返回值

Find 方法返回一个 *mongo.Cursor 对象,这是一个游标,可以迭代地访问查询结果中的文档。


示例1:查询 name=“Tom” 且 age>30 的第一个文档

既可以使用bson.D,也可以使用bson.M

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// 构建查询条件
// 使用bson.D类型
query1 := bson.D{
   {"name", "Tom"},
   {"age", bson.D{{"$gt", 30}}},
}
// 也可以使用bson.M类型
//query1 := bson.M{
//	"name": "Tom",
//	"age":  bson.M{"$gt": 30},
//}

// 将查询的结果保存到stu中
var stu Student
err = collection.FindOne(context.TODO(), query1).Decode(&stu)
if err != nil {
   log.Fatal(err)
}
fmt.Println(stu)

FindOne()方法返回的是*mongo.SingleResult类型,可以使用Decode()方法,将其保存到Student类型的变量中。

示例2:计算集合中所有文档的数量

查询条件为空,既可以使用bson.D,也可以使用bson.M

1
count, _ := collection.CountDocuments(context.TODO(), bson.M{}) // 也可以使用bson.D{}

示例3:计算年龄大于30的文档数量

1
2
filter := bson.M{"age": bson.M{"$gt": 30}}
count, _ = collection.CountDocuments(context.TODO(), filter)

示例4:查询集合中所有的文档

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
filter = bson.M{} // 创建空过滤器
// 获取MongoDB集合中所有的文档,并将结果存储在一个游标cursor中
cursor, _ := collection.Find(context.TODO(), filter)
// 遍历游标,处理查询结果
for cursor.Next(context.TODO()) {
    var stu Student
    if err := cursor.Decode(&stu); err != nil {
       log.Fatal(err)
    }
    fmt.Println(stu)
}

Find()方法返回的是*mongo.Cursor类型,可以cursor.Next()方法来对游标cursor进行遍历,在遍历到的游标位置,也可以调用Decode()方法,将其保存到Student类型的变量中。

示例5:查询分数在80到90的文档

1
2
filter = bson.M{"score": bson.M{"$gte": 80, "$lte": 90}}
cursor, _ = collection.Find(context.TODO(), filter)

示例6:或条件查询

查询name="Eric"age=36的文档

1
2
3
4
5
6
7
filter = bson.M{
    "$or": []bson.M{
       {"name": "Eric"},
       {"age": 36},
    },
}
cursor, _ = collection.Find(context.TODO(), filter)

示例7:将所有文档按照score降序

如果是单一排序条件,即可以使用bson.M,也可以使用bson.D

1
2
3
4
5
6
7
8
//sort := bson.M{
//  "score": -1, // score降序
//}
sort := bson.D{
    {"score", -1}, // score降序
}
opts := options.Find().SetSort(sort)
cursor, _ = collection.Find(context.TODO(), bson.M{}, opts)

示例8:将所有文档先按照score降序,再age升序

多排序条件,只能使用bson.D而不能使用bson.M,因为这里的排序是有先后顺序的。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 错误的写法:
//sort1 := bson.M{
//  "score": -1, // score降序
//  "age":   1,  // age升序
//}
// 正确的写法:
sort1 := bson.D{
    {"score", -1}, // score降序
    {"age", 1},    // age升序
}
opts = options.Find().SetSort(sort1)
cursor, _ = collection.Find(context.TODO(), bson.M{}, opts)

示例9:只查询前 3 个文档

1
2
limitOpts := options.Find().SetLimit(3)
cursor, _ = collection.Find(context.TODO(), bson.M{}, limitOpts)

示例10:跳过前 3 个文档

1
2
skipOpts := options.Find().SetSkip(3)
cursor, _ = collection.Find(context.TODO(), bson.M{}, skipOpts)

示例11:设置投影选项,只返回 name 和 score 字段,排除 _id 字段

1
2
3
projection := bson.M{"name": 1, "score": 1, "_id": 0}
projectionOpts := options.Find().SetProjection(projection)
cursor, _ = collection.Find(context.TODO(), bson.M{}, projectionOpts)

示例12:in 条件查询

查询班级为computer science 1computer science 2的文档:

1
2
3
4
5
6
filter = bson.M{
    "class": bson.M{
       "$in": []string{"computer science 1", "computer science 2"},
    },
}
cursor, _ = collection.Find(context.TODO(), filter)

示例13:查询存在 hobbies 字段的文档

1
2
3
4
5
6
filter = bson.M{
    "hobbies": bson.M{
       "$exists": true,
    },
}
cursor, _ = collection.Find(context.TODO(), filter)

插入

InsertOne 方法是 MongoDB Go 驱动程序中用于向集合中插入单个文档的函数。它是 mongo.Collection 类型的一个方法,允许你向指定的 MongoDB 集合中添加一个新文档。如果插入成功,它将返回一个包含新插入文档 ID 的结果,以及可能发生的任何错误。

InsertMany 方法的格式和InsertOne 方法相同。

方法签名

在 MongoDB Go 驱动程序中,InsertOne 方法的大致签名如下:

1
2
func (c *Collection) InsertOne(ctx context.Context, document interface{}, 
	opts ...*options.InsertOneOptions) (*InsertOneResult, error)
  • ctx context.Context:一个上下文对象,用于控制请求的生命周期,比如取消操作或设置超时时间。
  • document interface{}:要插入的文档,它应该是一个可以被编码为 BSON 的值,如 bson.Mbson.D、结构体等。
  • opts ...*options.InsertOneOptions:一个可选的参数列表,允许你指定额外的插入选项,比如绕过文档验证等。如果不需要这些选项,可以省略此参数。

返回值

  • *InsertOneResult:一个包含插入操作结果的对象。通常,你会关心这个对象中的 InsertedID 字段,它包含了新插入文档的 _id 字段的值(如果文档本身没有指定 _id,MongoDB 会自动生成一个)。
  • error:如果在插入过程中发生错误,将返回一个错误对象。你应该检查这个返回值以确定操作是否成功。

示例1:插入单个文档

既可以使用bson.D,也可以使用bson.M

使用bson.D

1
2
3
4
5
6
7
collection := client.Database("test").Collection("stus")
collection.InsertOne(context.TODO(), bson.D{
    {"name", "张三"},
    {"age", 20},
    {"gender", "男"},
    {"class", "计算机科学与技术1班"},
})

使用bson.M

1
2
3
4
5
6
7
collection.InsertOne(context.TODO(), bson.M{
    "name":   "李四",
    "age":    23,
    "gender": "男",
    "class":  "计算机科学与技术3班",
    "score":  69,
})

示例2:插入多个文档

和插入单个文档相同,都可以使用bson.Dbson.M

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 使用bson.D
//docs := []interface{}{
//  bson.D{
//     {"name", "张三"},
//     {"age", 20},
//     {"gender", "男"},
//     {"class", "计算机科学与技术1班"},
//  },
//  bson.D{
//     {"name", "李四"},
//     {"age", 21},
//     {"gender", "男"},
//     {"class", "计算机科学与技术2班"},
//  },
//}
// 使用bson.M
docs := []interface{}{
    bson.M{
       "name":   "张三",
       "age":    20,
       "gender": "男",
       "class":  "计算机科学与技术1班",
    },
    bson.M{
       "name":   "李四",
       "age":    21,
       "gender": "男",
       "class":  "计算机科学与技术2班",
    },
}
collection.InsertMany(context.TODO(), docs)

更新

collection.UpdateOne() 方法是 MongoDB Go 驱动程序中用于更新集合中符合特定查询条件的第一个文档的函数。它是 mongo.Collection 类型的一个方法,提供了灵活的方式来修改集合中的文档。以下是该方法的详细说明:

方法签名

在 MongoDB Go 驱动程序中,UpdateOne 方法的大致签名如下(注意:具体签名可能会根据驱动程序的版本而有所不同):

1
2
func (c *Collection) UpdateOne(ctx context.Context, filter interface{}, 
	update interface{}, opts ...*options.UpdateOptions) (*UpdateResult, error)
  • ctx context.Context:一个上下文对象,用于控制请求的生命周期,比如取消操作或设置超时时间。
  • filter interface{}:一个查询条件,用于指定要更新的文档。它应该是一个可以被编码为 BSON 的值,MongoDB 将使用这个条件来查找集合中的文档。
  • update interface{}:一个更新操作,指定了如何修改找到的文档。它应该是一个 BSON 文档,可以包含更新操作符(如 $set$inc 等)来指定更新操作。
  • opts ...*options.UpdateOptions:一个可选的参数列表,允许你指定额外的更新选项,比如是否进行乐观锁检查(通过版本字段)等。如果不需要这些选项,可以省略此参数。

返回值

  • *UpdateResult:一个包含更新操作结果的对象。它提供了关于更新操作的信息,如匹配到的文档数(MatchedCount)和实际更新的文档数(ModifiedCount)。在某些情况下,这两个值可能不同,比如当更新操作实际上没有改变文档的内容时。

    UpdateResult结构体的详细说明

    UpdateResult结构体有4个字段:

    1. MatchedCount:这个字段表示通过查询条件(filter)匹配到的文档数量。即使这些文档中的某些或全部没有被实际修改(比如,因为更新操作与文档当前状态相同),MatchedCount 也会反映匹配到的文档总数。

    2. ModifiedCount:这个字段表示被更新操作实际修改的文档数量。在某些情况下,ModifiedCount 可能小于 MatchedCount,比如当更新操作实际上没有改变文档的内容时(比如,使用 $set 操作符设置字段的当前值)。

    3. UpsertedCount:这个字段表示由于执行了 upsert 操作(即“如果未找到则插入”)而新增的文档数量。Upsert 是一种特殊的更新操作,当查询条件未匹配到任何文档时,它允许你插入一个新的文档。

      UpsertedCount 通常在 0(没有执行 upsert)和 1(执行了一个 upsert)之间变化,因为 MongoDB 的 upsert 操作每次只影响一个文档(要么更新一个现有文档,要么插入一个新文档)。

    4. UpsertedID:这个字段包含了由于执行 upsert 操作而插入的文档的 _id 字段值,或者如果没有执行 upsert 操作则为 nil。这对于获取新插入文档的唯一标识符非常有用。请注意,UpsertedID 的类型是 interface{},这意味着它可以包含任何 BSON 类型的值,但通常你会期望它是一个基本类型(如 stringint64bson.ObjectId),具体取决于你的文档结构和 MongoDB 的配置。

  • error:如果在更新过程中发生错误,将返回一个错误对象。你应该检查这个返回值以确定操作是否成功。

示例1:将name=“Alice"的文档的score改为85

既可以使用bson.D,也可以使用bson.M

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// 获取集合
collection := client.Database("test").Collection("stus")
// 使用bson.D
// 构建查询条件
// filter := bson.D{{"name", "Alice"}}
// 构建更新操作
// update := bson.D{{"$set", bson.D{{"score", 85}}}}
// 使用bson.M
filter := bson.M{"name": "Alice"}
update := bson.M{"$set": bson.M{"score": 84}}
// 执行 updateOne 操作
result, _ := collection.UpdateOne(context.TODO(), filter, update)
// 打印更新结果
fmt.Printf("Matched %v documents and updated %v documents.\n", result.MatchedCount, result.ModifiedCount)

示例2:更新多个文档

1
2
3
filter = bson.M{"class": "computer science 1"}
update = bson.M{"$inc": bson.M{"score": -5}}
collection.UpdateMany(context.TODO(), filter, update)

示例3:替换整个文档

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
filter = bson.M{"name": "Denny"}
replacement := bson.M{
    "name":   "Dennis",
    "age":    29,
    "gender": "male",
    "class":  "computer science 1",
    "score":  92,
}
// 执行 replaceOne 操作
collection.ReplaceOne(context.TODO(), filter, replacement)

示例4:使用 upsert 选项

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
filter = bson.M{"name": "Charlie", "age": 22}
update = bson.M{"$set": bson.M{
    "name":   "Charlie",
    "age":    22,
    "gender": "male",
    "class":  "computer science 3",
    "score":  99,
}}
// 构建选项以启用upsert
opts := options.Update().SetUpsert(true)
// 执行updateOne操作
collection.UpdateOne(context.TODO(), filter, update, opts)

示例 5:从文档中移除指定的字段

1
2
3
4
5
6
7
8
filter = bson.M{"name": "Eric"}
// 构建更新操作,使用$unset来移除score字段
update = bson.M{"$unset": bson.M{"score": 1}}
// 注意:在$unset操作中,字段的值实际上并不重要,因为$unset是根据字段名来移除字段的。
// 但为了与MongoDB shell中的语法保持一致,这里仍然给出了值1。
// 在实际使用中,你也可以省略这个值,直接写bson.M{"score": ""}或完全忽略值(虽然这可能会影响代码的可读性)。
// 执行updateOne操作
collection.UpdateOne(context.TODO(), filter, update)

删除

collection.DeleteOne() 方法是 MongoDB Go 驱动程序中的一个函数,用于从 MongoDB 集合中删除一个与给定过滤器匹配的文档。这个方法是 *mongo.Collection 类型的一个方法,表示对 MongoDB 集合的操作。

函数签名

在 MongoDB Go 驱动程序中,DeleteOne 方法的函数签名大致如下(注意:具体签名可能会根据 MongoDB Go 驱动程序的版本而略有不同):

1
2
func (c *Collection) DeleteOne(ctx context.Context, filter interface{}, 
	opts ...*options.DeleteOptions) (*DeleteResult, error)
  • ctx context.Context:一个上下文对象,用于控制请求的取消、超时和截止日期。虽然 context.TODO() 可以用于简单的示例或测试,但在生产代码中,你应该传递一个具有适当超时和取消逻辑的上下文。
  • filter interface{}:一个用于指定要删除的文档的选择器的接口。在 MongoDB Go 驱动程序中,这通常是一个 bson.Mbson.D 类型的值,用于构建查询条件。
  • opts ...*options.DeleteOptions:一个可选的 *options.DeleteOptions 类型的切片,用于指定额外的删除选项,如写关注(write concern)或投影(虽然对于删除操作来说,投影并不适用)。

返回值

  • *DeleteResult:一个指向 DeleteResult 结构的指针,该结构包含关于删除操作的信息,如被删除的文档数(对于 DeleteOne 来说,这将是 0 或 1)。
  • error:如果在执行删除操作时发生错误,则返回该错误。

示例1:

示例 1:删除单个文档

要删除名为 “张三” 的学生的文档

1
2
3
4
5
6
7
// 获取集合
collection := client.Database("test").Collection("stus")
// 构建过滤器
filter := bson.M{"name": "张三"}
// 执行deleteOne操作
result, _ := collection.DeleteOne(context.TODO(), filter)
fmt.Println("删除文档的数量:", result.DeletedCount)

示例 2:删除多个文档

要删除所有名为 “张三” 的学生的文档

1
2
3
4
filter := bson.M{"name": "张三"}
// 执行deleteMany操作
deleteResult, _ := collection.DeleteMany(context.TODO(), filter)
fmt.Println("删除文档的数量:", deleteResult.DeletedCount)

示例 3:删除所有文档(慎用)

1
2
3
4
5
6
7
filter := bson.M{} // 构建一个空的查询过滤器
// 执行deleteMany操作以删除所有文档
deleteResult, _ = collection.DeleteMany(context.TODO(), filter)
fmt.Println("删除文档的数量:", deleteResult.DeletedCount)

// 或者使用drop()来删除集合
collection.Drop(context.TODO())

内嵌文档

示例1:给name=“Alice"的文档添加hobbies属性,hobbies也有两个属性:cities和sports

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// 获取集合
collection := client.Database("test").Collection("stus")
// 构建查询过滤器
filter := bson.M{"name": "Tom"}
// 构建更新文档
update := bson.M{
    "$set": bson.M{
       "hobbies": bson.M{
          "cities": []string{"shenzhen", "New York"},
          "sports": []string{"skiing", "mountaineering"},
       },
    },
}
// 执行updateOne操作
result, _ := collection.UpdateOne(context.TODO(), filter, update)
fmt.Printf("Matched %v documents and updated %v documents.\n", result.MatchedCount, result.ModifiedCount)

示例2:查询所有 hobbies.cities 数组中包含 “shenzhen” 的文档

1
2
3
4
5
6
7
8
filter := bson.M{"hobbies.cities": "shenzhen"}
cursor, err := collection.Find(context.TODO(), filter)
defer cursor.Close(context.TODO())
for cursor.Next(context.TODO()) {
    var stu Student
    cursor.Decode(&stu)
    fmt.Println(stu)
}

示例3:将 Alice 喜欢的城市添加一个 “chengdu”

1
2
3
4
5
6
7
8
filter := bson.M{"name": "Alice"}
update := bson.M{
    "$push": bson.M{
       "hobbies.cities": "chengdu",
    },
}
// 执行updateOne操作
collection.UpdateOne(context.TODO(), filter, update)

执行多次会多次添加。

示例4:如果 Alice 喜欢的城市没有 “chengdu”,则添加该城市,否则什么也不做

1
2
3
4
5
6
7
8
filter := bson.M{"name": "Alice"}
update := bson.M{
    "$addToSet": bson.M{
       "hobbies.cities": "chengdu",
    },
}
// 执行updateOne操作
collection.UpdateOne(context.TODO(), filter, update)

执行多次也只会添加一次。

示例5:从 Alice 的 hobbies.cities 数组中删除刚才添加的 “chengdu”

1
2
3
4
5
6
7
filter := bson.M{"name": "Alice"}
update := bson.M{
    "$pull": bson.M{
       "hobbies.cities": "chengdu",
    },
}
collection.UpdateOne(context.TODO(), filter, update)

这个 updateOne 操作会找到 name 为 “Alice” 的第一个文档,并从其 hobbies.cities 数组中移除所有值为 “chengdu” 的元素。

0%