目录
[match](#match)
[group](#group)
[project](#project)
[sort](#sort)
[limit](#limit)
[skip](#skip)
[lookup](#lookup)
[unwind](#unwind)
MongoDB是一个流行的NoSQL数据库,而Go语言是一种简洁、高效的编程语言。这两者组合可以给应用程序提供强大的数据存储和操作能力。
在Go语言中操作MongoDB需要使用官方MongoDB Go驱动程序。以下总结下在Go语言中使用MongoDB数据库涉及到的一些基本操作。如插入文档、查询文档,如何在Go中进行连接、增、删、改、查等常用操作,以及如何使用聚合管道进行复杂查询。
前提条件
1.确保您已经安装了MongoDB和Go语言环境。
2.安装MongoDB Go驱动程序,可以使用go get
命令来安装:
go get go.mongodb.org/mongo-driver/mongo
新建个项目文件夹,在下面新建main.go文件,执行yourprj换成你的包名。
bash
go mod init yourprj
不用非得执行上面的go get 方式,直接项目代码中import需要的包,执行go mod tidy即可。
连接到MongoDB
首先,需要连接到MongoDB实例:
Go
package main
import (
"context"
"log"
"time"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func main() {
clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
client, err := mongo.Connect(ctx, clientOptions)
if err != nil {
log.Fatal(err)
}
defer func() {
if err = client.Disconnect(ctx); err != nil {
log.Fatal(err)
}
}()
// 获取数据库和集合
db := client.Database("testDB")
collection := db.Collection("users")
// 接下来的操作在这里进行
}
注意事项
上面的连接url参数针对未开启认证的可以连接成功,若开启有用户名密码验证则需要类似如下的连接参数:
bash
"mongodb://user:yourpwd@localhost:27017/?tls=false&authSource=test1"
简单示例
bash
package main
import (
"context"
"fmt"
"log"
"time"
//"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/bson"
)
type User struct {
Name string `json:"name"`
Email string `json:"email"`
Age int `bson:"Agg"`
}
// ... 上面User结构体定义 ...
func main() {
// 连接MongoDB
clientOptions := options.Client().ApplyURI("mongodb://test1:111111@localhost:27017/?tls=false&authSource=test1")
client, err := mongo.Connect(context.Background(), clientOptions)
if err != nil {
log.Fatal(err)
}
defer func() {
if err = client.Disconnect(context.Background()); err != nil {
log.Fatal(err)
}
}()
// 解析JSON字符串到User结构体(假设已经完成)
user := User{Name: "Alice", Email: "alice@example.com",Age:22}
// 选择数据库和集合
collection := client.Database("test1").Collection("users")
// 插入文档
insertResult, err := collection.InsertOne(context.TODO(), user)
if err != nil {
log.Fatal(err)
}
fmt.Println("Inserted ID:", insertResult.InsertedID)
// 插入文档
doc := bson.D{{"age", 30},{"name", "Alice2"}, {"createdAt", time.Now()}}
insertResult, err = collection.InsertOne(context.TODO(), doc)
if err != nil {
log.Fatal(err)
}
fmt.Println("Inserted ID:", insertResult.InsertedID)
// 更新文档
filter := bson.D{{"name", "Alice1"}}
update := bson.D{{"$set", bson.D{{"age", 31}}}}
updateResult, err := collection.UpdateOne(context.TODO(), filter, update)
if err != nil {
log.Fatal(err)
}
fmt.Println("Modified Count:", updateResult.ModifiedCount)
// 删除文档
filter = bson.D{{"age", 22}}
deleteResult, err := collection.DeleteOne(context.TODO(), filter)
if err != nil {
log.Fatal(err)
}
fmt.Println("Deleted Count:", deleteResult.DeletedCount)
// 查找单个文档
var singleResult bson.M
err = collection.FindOne(context.TODO(), bson.D{}).Decode(&singleResult)
if err != nil {
log.Fatal(err)
}
fmt.Println("Single Document:", singleResult)
// 查找所有文档
cursor, err := collection.Find(context.TODO(), bson.D{})
if err != nil {
log.Fatal(err)
}
defer cursor.Close(context.TODO())
for cursor.Next(context.TODO()) {
var result bson.M
err := cursor.Decode(&result)
if err != nil {
log.Fatal(err)
}
fmt.Println("Document:", result)
}
// 过滤查找
filteredCursor, err := collection.Find(context.TODO(), bson.D{{"age", bson.D{{"$gt", 31}}}})
if err != nil {
log.Fatal(err)
}
defer filteredCursor.Close(context.TODO())
for filteredCursor.Next(context.TODO()) {
var filteredDoc bson.M
err := filteredCursor.Decode(&filteredDoc)
if err != nil {
log.Fatal(err)
}
fmt.Println("Filtered Document:", filteredDoc)
}
}
插入文档
Go
user := map[string]interface{}{"name": "Alice", "age": 29}
_, err = collection.InsertOne(ctx, user)
if err != nil {
log.Fatal(err)
}
users := []interface{}{
map[string]interface{}{"name": "Bob", "age": 31},
map[string]interface{}{"name": "Charlie", "age": 25},
}
_, err = collection.InsertMany(ctx, users)
if err != nil {
log.Fatal(err)
}
查询文档
查询单个文档
Go
var result map[string]interface{}
filter := map[string]interface{}{"name": "Alice"}
err = collection.FindOne(ctx, filter).Decode(&result)
if err != nil {
log.Fatal(err)
}
log.Println(result)
查询多个文档
Go
filter = map[string]interface{}{"age": map[string]interface{}{"$gte": 30}}
cursor, err := collection.Find(ctx, filter)
if err != nil {
log.Fatal(err)
}
defer cursor.Close(ctx)
var results []map[string]interface{}
if err = cursor.All(ctx, &results); err != nil {
log.Fatal(err)
}
for _, result := range results {
log.Println(result)
}
更新文档
更新单个文档
Go
filter = map[string]interface{}{"name": "Bob"}
update := map[string]interface{}{"$set": map[string]interface{}{"age": 32}}
_, err = collection.UpdateOne(ctx, filter, update)
if err != nil {
log.Fatal(err)
}
更新多个文档
Go
filter = map[string]interface{}{"age": map[string]interface{}{"$lt": 30}}
update = map[string]interface{}{"$set": map[string]interface{}{"valid": true}}
_, err = collection.UpdateMany(ctx, filter, update)
if err != nil {
log.Fatal(err)
}
删除文档
删除单个文档
Go
filter = map[string]interface{}{"name": "Charlie"}
_, err = collection.DeleteOne(ctx, filter)
if err != nil {
log.Fatal(err)
}
删除多个文档
Go
filter = map[string]interface{}{"valid": true}
_, err = collection.DeleteMany(ctx, filter)
if err != nil {
log.Fatal(err)
}
聚合管道
MongoDB的聚合管道(Aggregation Pipeline)是一种强大的数据处理工具,它允许用户对集合中的文档执行一系列数据转换和处理操作。聚合管道由一系列的阶段(stages)组成,每个阶段会对输入的文档进行一定的操作并将结果传递到下一个阶段。
每个阶段都是一个管道操作符(pipeline operator),共同组成一个管道。常见的管道操作符包括 $match
、$group
、$project
、$sort
、$limit
等。
bash
聚合管道的基本结构
聚合管道通过 aggregate 方法来执行。其基本结构如下:
db.collection.aggregate([
{ $stage1: {...} },
{ $stage2: {...} },
...
])
常见聚合操作符
以下是一些常见的聚合操作符及其作用:
$match
用来过滤文档,其作用类似于 SQL 中的 WHERE
子句。
{ $match: { age: { $gte: 25 } } }
$group
将文档分组,并可以对每个分组应用聚合函数,如计数、求和、平均值等。
{ $group: { _id: "$age", count: { $sum: 1 } } }
$project
用于重新塑造文档,可以用来包括、排除或重命名字段。
{ $project: { name: 1, age: 1, _id: 0 } }
$sort
对文档进行排序。
{ $sort: { age: -1 } }
$limit
限制返回的文档数量。
{ $limit: 10 }
$skip
跳过指定数量的文档。
{ $skip: 5 }
$lookup
用于执行左外连接。
{ $lookup: { from: "otherCollection", localField: "fieldA", foreignField: "fieldB", as: "newField" } }
$unwind
将数组类型字段中的每个值拆分成单独的文档。
{ $unwind: "$arrayField" }
示例
下面是一个使用 aggregate
方法的具体示例,展示了如何使用聚合管道操作符:
bash
db.users.aggregate([
// 匹配 age 大于等于 25 的文档
{ $match: { age: { $gte: 25 } } },
// 按照 age 分组,并计算每个分组的数量
{ $group: { _id: "$age", count: { $sum: 1 } } },
// 按照 count 字段降序排序
{ $sort: { count: -1 } },
// 仅保留前 5 个结果
{ $limit: 5 }
])
Go中的聚合管道使用示例
Go
package main
import (
"context"
"log"
"time"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func main() {
clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
client, err := mongo.Connect(ctx, clientOptions)
if err != nil {
log.Fatal(err)
}
defer func() {
if err = client.Disconnect(ctx); err != nil {
log.Fatal(err)
}
}()
db := client.Database("testDB")
collection := db.Collection("users")
pipeline := mongo.Pipeline{
{{Key: "$match", Value: map[string]interface{}{"age": map[string]interface{}{"$gte": 25}}}},
{{Key: "$group", Value: map[string]interface{}{"_id": "$age", "count": map[string]interface{}{"$sum": 1}}}},
{{Key: "$sort", Value: map[string]interface{}{"count": -1}}},
{{Key: "$limit", Value: int32(5)}},
}
cursor, err := collection.Aggregate(ctx, pipeline)
if err != nil {
log.Fatal(err)
}
defer cursor.Close(ctx)
var results []map[string]interface{}
if err = cursor.All(ctx, &results); err != nil {
log.Fatal(err)
}
for _, result := range results {
log.Println(result)
}
}
Go
pipeline := mongo.Pipeline{
{{Key: "$match", Value: map[string]interface{}{"age": map[string]interface{}{"$gte": 25}}}},
{{Key: "$group", Value: map[string]interface{}{"_id": "$age", "count": map[string]interface{}{"$sum": 1}}}},
}
cursor, err = collection.Aggregate(ctx, pipeline)
if err != nil {
log.Fatal(err)
}
defer cursor.Close(ctx)
var pipelineResults []map[string]interface{}
if err = cursor.All(ctx, &pipelineResults); err != nil {
log.Fatal(err)
}
for _, result := range pipelineResults {
log.Println(result)
}
完整示例
Go
package main
import (
"context"
"log"
"time"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func main() {
clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
client, err := mongo.Connect(ctx, clientOptions)
if err != nil {
log.Fatal(err)
}
defer func() {
if err = client.Disconnect(ctx); err != nil {
log.Fatal(err)
}
}()
db := client.Database("testDB")
collection := db.Collection("users")
// 插入文档
collection.InsertOne(ctx, map[string]interface{}{"name": "Alice", "age": 29})
collection.InsertMany(ctx, []interface{}{
map[string]interface{}{"name": "Bob", "age": 31},
map[string]interface{}{"name": "Charlie", "age": 25},
})
// 查询单个文档
var result map[string]interface{}
collection.FindOne(ctx, map[string]interface{}{"name": "Alice"}).Decode(&result)
log.Println(result)
// 查询多个文档
cursor, err := collection.Find(ctx, map[string]interface{}{"age": map[string]interface{}{"$gte": 30}})
if err != nil {
log.Fatal(err)
}
defer cursor.Close(ctx)
var results []map[string]interface{}
cursor.All(ctx, &results)
for _, res := range results {
log.Println(res)
}
// 更新文档
collection.UpdateOne(ctx, map[string]interface{}{"name": "Bob"}, map[string]interface{}{"$set": map[string]interface{}{"age": 32}})
collection.UpdateMany(ctx, map[string]interface{}{"age": map[string]interface{}{"$lt": 30}}, map[string]interface{}{"$set": map[string]interface{}{"valid": true}})
// 删除文档
collection.DeleteOne(ctx, map[string]interface{}{"name": "Charlie"})
collection.DeleteMany(ctx, map[string]interface{}{"valid": true})
// 聚合管道
pipeline := mongo.Pipeline{
{{Key: "$match", Value: map[string]interface{}{"age": map[string]interface{}{"$gte": 25}}}},
{{Key: "$group", Value: map[string]interface{}{"_id": "$age", "count": map[string]interface{}{"$sum": 1}}}},
}
cursor, err = collection.Aggregate(ctx, pipeline)
if err != nil {
log.Fatal(err)
}
defer cursor.Close(ctx)
var pipelineResults []map[string]interface{}
cursor.All(ctx, &pipelineResults)
for _, res := range pipelineResults {
log.Println(res)
}
}