MongoDB

2026年1月14日 · 552 字 · 3 分钟

介绍了mongoDB的基本语法,以及在go中操作mongoDB

MongoDB

一、MongoDB 是什么

MongoDB 是典型的 文档型数据库(Document DB),数据以 BSON(类似 JSON)形式存储。它的核心优势是:

  • 结构灵活:同一个集合里,不同文档字段可以不同(你后面插入“张三/李四”就是典型例子)。
  • 开发效率高:对象结构和 JSON 很接近,适合快速迭代。
  • 横向扩展能力强:天然适合分片、复制集等分布式方案(适合海量数据与高并发)。

二、MongoDB 典型应用场景

1)内容/信息流类(字段经常变、迭代快)

比如:博客文章、评论、点赞、标签、用户行为记录。 特点:字段可能不断新增(阅读量、推荐权重、AB实验分组……),MongoDB 的“无固定表结构”很省事。

2)日志与埋点数据(写多读少、数据量大)

如:访问日志、系统日志、业务埋点。 MongoDB 写入性能好,配合索引和分片可承载较大吞吐。

3)用户画像/配置中心(每个人字段不一样)

如:用户偏好、标签、权限、个性化配置。 不同用户属性差异大,用关系型表会变成“稀疏列/多表拆分”,MongoDB 反而自然。

4)原型验证与快速开发

项目早期需求不稳定,MongoDB 可以让你先把功能跑通,再逐步优化模型。

不太建议:强事务、强一致、多表复杂 JOIN 的场景(虽然 MongoDB 支持事务,但复杂关联依旧不是它的强项)。


三、MongoDB 基本语法


1)查看集合

test> show collections

作用:列出当前数据库 test 下所有集合(类似 MySQL 的 show tables)。


2)创建集合

test> db.createCollection("student")
{ ok: 1 }

db.createCollection("student"):显式创建集合 student。 MongoDB 其实也支持 隐式创建:当你第一次向 student 插入数据时,如果集合不存在,也会自动创建。

验证:

test> show collections
student

3)创建索引:你遇到的坑

MongoDB 的 createIndex() 参数里:

  • 第一个参数是 key(字段与排序方向)
  • 第二个参数才是 options(例如 unique)
db.student.createIndex({ name: 1 }, { unique: true })

4)查看索引

test> db.student.getIndexes()
[
  { v: 2, key: { _id: 1 }, name: '_id_' },
  { v: 2, key: { name: 1 }, name: 'name_1', unique: true }
]

解释:

  • MongoDB 默认每个集合都有 _id_ 索引(主键)。

5)删除索引

test> db.student.dropIndex("name_1")
{ nIndexesWas: 2, ok: 1 }

删除指定名字的索引(索引名来自 createIndex 返回值)。

再查:

test> db.student.getIndexes()
[ { v: 2, key: { _id: 1 }, name: '_id_' } ]

只剩默认 _id_


6)重新创建一个普通索引

test> db.student.createIndex({name:1})
name_1

单字段升序索引:对 name 的查询会更快,例如 find({name:"张三"})


四、插入数据 insert

1)插入一条

db.student.insertOne({name:"张三",city:"北京"})

返回 insertedId,MongoDB 自动生成 _id(ObjectId)。

2)查询全部

db.student.find()

你看到集合里有一条文档。

3)批量插入

db.student.insertMany([{name:"张三",city:"北京"},{name:"李四",gender:"男"}])

特点:

  • 同一个集合里,第二条文档没有 city,却有 gender —— 这就是 MongoDB 的“字段灵活”。

五、查询 find(带条件)

db.student.find({name:"张三"})

返回所有 name="张三" 的文档。 这个查询会受益于你之前建的 name_1 索引。


六、更新 update

1)更新一条 updateOne

db.student.updateOne({name:"张三"},{$set:{gender:"女"}})

解释:

  • {name:"张三"}:过滤条件(匹配第一条符合条件的文档)
  • {$set:{gender:"女"}}:更新操作符(只改 gender 字段,不会覆盖整个文档)

返回值里:

  • matchedCount: 1:匹配到 1 条
  • modifiedCount: 1:实际修改 1 条

再查:

db.student.find({name:"张三"})

你会发现:只有其中一个张三有 gender 字段。

2)更新多条 updateMany

db.student.updateMany({name:"张三"},{$set:{city:"上海"}})

匹配到的两条张三都被更新为 city:"上海"


七、删除 delete

1)删除一条 deleteOne

db.student.deleteOne({name:"张三"})

只删第一条匹配到的张三。

2)删除多条 deleteMany

db.student.deleteMany({name:"张三"})

删除所有匹配到的张三。


八、删除集合 drop

db.student.drop()
true

删除整个集合(数据 + 索引都会没)。

验证:

show collections

student 不见了。


九、总结

  • show collections:查看集合
  • db.createCollection():创建集合(也可插入时自动创建)
  • createIndex / getIndexes / dropIndex:索引管理(注意 unique 是 options,不是 key)
  • insertOne / insertMany:插入
  • find(条件):查询
  • updateOne / updateMany + $set:更新
  • deleteOne / deleteMany:删除
  • drop():删集合

go操作mongoDB

连接mongoDB

func MongoDBInit() {
	ctx := context.Background()
	option := options.Client().ApplyURI("mongodb://localhost:27017").
		SetConnectTimeout(time.Second). //设置超时时长
		SetAuth(options.Credential{
			//AuthSource代表Database
			Username:   "",
			Password:   "",
			AuthSource: "test",
		})
	client, err := mongo.Connect(ctx, option)
	if err != nil {
		log.Fatal(err)
	}
	//Connect没有返回error不代表连接成功,ping一下检查是否连接成功
	err = client.Ping(ctx, nil)
	if err != nil {
		log.Fatal(err)
	}
	defer client.Disconnect(ctx) //释放连接

	collection := client.Database("test").Collection("student")
	//增
	create(ctx, collection)
	//改
	update(ctx, collection)
	//删
	delete(ctx, collection)
	//查
	find(ctx, collection)
}

type Student struct {
	Name  string
	City  string
	Score float32
}

func create(ctx context.Context, collection *mongo.Collection) {
	//插入一个doc
	student := Student{
		Name:  "张三",
		City:  "北京",
		Score: 85.5,
	}
	res, err := collection.InsertOne(ctx, student)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("插入成功", res.InsertedID) //每个doc都会有一个全世界唯一的ID(时间+空间唯一)

	//插入多个docs
	docs := []interface{}{Student{Name: "李四", City: "北京", Score: 24}, Student{Name: "王五", City: "南京", Score: 21}}
	manyRes, err := collection.InsertMany(ctx, docs)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("插入多个doc成功", manyRes.InsertedIDs)
}

func delete(ctx context.Context, collection *mongo.Collection) {
	//删除一个doc
	filter := bson.D{{Key: "name", Value: "张三"}}
	//切片过滤条件可以有多个
	res, err := collection.DeleteMany(ctx, filter)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("删除成功", res.DeletedCount)
}

func update(ctx context.Context, collection *mongo.Collection) {
	//更新一个doc
	filter := bson.D{{Key: "city", Value: "北京"}}
	//切片过滤条件可以有多个
	//把满足在北京的学生,score加上5
	update := bson.D{{Key: "$inc", Value: bson.D{{Key: "score", Value: 5}}}}
	//切片更新条件可以有多个
	res, err := collection.UpdateMany(ctx, filter, update)
	if err != nil {
		log.Fatal(err)
	}
	//打印修改了多少条记录
	fmt.Println("更新成功", res.ModifiedCount)
}

func find(ctx context.Context, collection *mongo.Collection) {
	//查询一个doc
	sort := bson.D{{Key: "name", Value: 1}} //查询结果按name进行排序。1代表升序,-1代表降序
	//gt代表greater than
	filter := bson.D{{Key: "score", Value: bson.D{{Key: "$gt", Value: 3}}}} //查询结果按score大于3进行过滤
	//切片过滤条件可以有多个
	findOptions := options.Find()
	findOptions.SetSort(sort)
	findOptions.SetLimit(10) //限制查询结果最多10条
	findOptions.SetSkip(3)   //跳过前3个

	cursor, err := collection.Find(ctx, filter, findOptions)
	if err != nil {
		log.Fatal(err)
	}
	defer cursor.Close(ctx) //关闭迭代器
	for cursor.Next(ctx) {
		var student Student
		if err = cursor.Decode(&student); err != nil {
			log.Fatal(err)
		}
		fmt.Println("查询成功", student.Name, student.City, student.Score)
	}
}