MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。
它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型
mongo应用场景
MongoDB 和 MySQL 是两种不同类型的数据库(分别属于 NoSQL 和关系型数据库),适用场景和核心特性有显著区别
对于关系型数据库来说,我们开发的时候,需要先定义好表、字段这些,后期如果要扩展字段这些相对来说比较麻烦
但是对于非关系型数据库来说,开发的时候就不需要提前定义表和字段这些了,适合快速迭代以及差异化展示
- 内容管理系统(CMS)
存储文章、评论、用户生成内容等,这些数据往往结构多变(例如不同文章可能有不同字段:视频文章有 “时长”,图文文章有 “图片列表”),MongoDB 的文档模型可以直接嵌套存储,无需像 MySQL 那样拆分成多张表。
- 大数据与实时分析
支持高并发写入和水平扩展(分片),适合存储日志、埋点数据、传感器数据等海量时序数据,可快速写入并通过聚合管道进行实时分析。
- 移动 / 物联网(IoT)应用
设备采集的非结构化数据(如设备状态、地理位置、传感器读数)可以直接以文档形式存储,无需预先定义严格 schema,方便适配不同设备的数据格式。
- 社交应用
存储用户动态、关系链、消息记录等,文档模型支持嵌套数组(如 “好友列表”“评论列表”),避免 MySQL 中多表关联查询的性能开销。
- 电商平台
存储商品信息(不同商品属性差异大:服装有 “尺码”,电子设备有 “参数”)、购物车、订单等,灵活的 schema 可快速适配业务变化。
mongodb安装
拉取镜像
docker pull mongo:8.0.15
创建容器,并创建用户和数据库
docker run --name mongo -p 27017:27017 -v /home/mongo:/data/db -d mongo:8.0.15
docker exec -it mongo bash
# 进入mongo的shell
mongosh
# 创建并进入数据库 test
use test
# 创建用户并授权
db.createUser({
user: "root1",
pwd: "root1",
roles: [{ role: "dbOwner", db: "test" }]
})
# 验证用户是否创建成功
show users
# 创建的这个root1用户,只能访问test这个数据库
# 后续进入数据库
mongosh -u root1 -p root1 test
也可以直接在启动容器的时候,创建用户名和密码
docker run --name mongo -p 27017:27017 -v /home/mongo:/data/db -e MONGO_INITDB_ROOT_USERNAME=root -e MONGO_INITDB_ROOT_PASSWORD=root -d mongo:8.0.15 --auth
# 通过此命令创建的用户,可以进所有用户创建的数据库,不过要指定认证数据库
mongosh -u root -p root --authenticationDatabase admin test
但是还是需要手动创建数据库,不过可以在客户端里面创建
mongo客户端
可以使用goland里面的mongodb客户端
后续学习mongo的基本命令,也是基于此客户端

mongodb基本命令
就和学习mysql一样,我们需要先了解mongo的基本命令
基本操作
// 查看数据库
show databases
// 创建数据库
use test
// 查看所有集合
show collections
// 创建集合
db.createCollection("user")
// 删除集合
db.user.drop()
// 删除库
db.dropDatabase()
// 创建文档
db.user.insert({"name": "fengfeng"})
db.user.insert({"name": "fengfeng", "age": 21})
db.user.insertOne({name: "王五"})
// 如果集合不存在,会自动创建
db.student.insertOne({name: "王五"})
// 批量创建文档
db.user.insertMany([{name: "lisi"}, {name: "张三"}])
// 创建的时候,指定id
db.user.insertOne({_id: 110, name: "yuanfang"})
// 使用for循环批量创建
for(let i=1;i<10;i++){
db.user.insertOne({name:"a"+i,age:i})
}
// 查询文档
db.user.find()
// 删除 db.集合名.remove(条件 [,是否删除一条])
// 删除全部文档
db.user.remove({}, false)
// 删除满足条件的一条文档 指定id删除
db.user.remove({_id: ObjectId("68e8b50129427f6eb783f216")}, true)
// 指定其他条件删除
db.user.remove({name: "a8"}, true)
// 修改文档 db.集合名.update(条件, 新数据 [,是否新增, 是否修改多条])
// 把 a7换成a77
db.user.update({name:"a7"},{$set: {name:"a77"}})
查询
// 查询 db.集合名.find(条件 [,查询的列])
// 查询全部
db.user.find()
// 带条件查询 查询age大于5的
db.user.find({age: {$gt: 5}})
// 带条件查询 查询name 在区间内的
db.user.find({name: {$in: ["a1", "a2"]}})
// 只显示name列
db.user.find({}, {name: 1, _id: 0})
// 排序
db.user.find().sort({age: -1}) // 1 升序 -1 降序
// 分页
db.user.find()
db.user.find().limit(2) // 查询前两条数据
db.user.find().skip(2).limit(2) // 跳过两条,查询两条数据
运算符
| 运算符 | 作用 |
|---|---|
| $gt | 大于 |
| $gte | 大于等于 |
| $lt | 小于 |
| $lte | 小于等于 |
| $ne | 不等于 |
| $in | in |
| $nin | not in |
聚合查询
// 准备数据
db.people.insert({_id: 1, name: "a", sex: "男", age: 21})
db.people.insert({_id: 2, name: "b", sex: "男", age: 20})
db.people.insert({_id: 3, name: "c", sex: "女", age: 20})
db.people.insert({_id: 4, name: "d", sex: "女", age: 18})
db.people.insert({_id: 5, name: "e", sex: "男", age: 19})
// 统计男生、女生的总年龄
db.people.aggregate([
{$group: {_id: "$sex", age_sum: {$sum: "$age"}}}
])
// 统计男生女生的总人数
db.people.aggregate([
{$group: {_id: "$sex", sum: {$sum: 1}}}
])
// 求学生总数和平均年龄
db.people.aggregate([
{$group: {_id: null, total_num: {$sum: 1}, total_avg: {$avg: "$age"}}}
])
// 查询男生、女生人数,按人数升序
db.people.aggregate([
{$group: {_id: "$sex", rs: {$sum: 1}}},
{$sort: {rs: 1}}
])
常用管道
| $group | 将集合中的文档分组,用于统计结果 |
|---|---|
| $match | 过滤数据,只输出符合条件的文档 |
| $sort | 聚合数据进一步排序 |
| $skip | 跳过指定文档数 |
| $limit | 限制集合数据返回文档数 |
常用表达式
| $sum | 总和($num:1同count表示统计) |
|---|---|
| $avg | 平均 |
| $min | 最小值 |
| $max | 最大值 |
go操作mongodb
其实mongo更适合在nodejs和python这类动态语言中进行使用
在go里面,我们掌握基本的mongo操作就可以了
重点还是要对mongo的原生操作熟悉
使用的库
go get go.mongodb.org/mongo-driver/mongo
基本连接
package main
import (
"context"
"fmt"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"log"
)
func main() {
// 设置客户端连接配置
clientOptions := options.Client().
ApplyURI("mongodb://192.168.80.170:27017").
SetAuth(options.Credential{
Username: "root",
Password: "root",
}). // 用户名和密码
SetMaxPoolSize(100). // 最大连接数
SetMinPoolSize(10) // 最小连接数
// 连接到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!")
// 断开连接
err = client.Disconnect(context.TODO())
if err != nil {
log.Fatal(err)
}
fmt.Println("Connection to MongoDB closed.")
}
crud操作
插入数据
package main
import (
"context"
"fmt"
"go.mongodb.org/mongo-driver/bson"
)
func main() {
insert3()
}
func insert1() {
collection := client.Database("test").Collection("users")
data := bson.D{
{
Key: "name",
Value: "fengfeng",
},
{
Key: "age",
Value: 18,
},
}
result, err := collection.InsertOne(context.Background(), data)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(result.InsertedID)
}
func insert2() {
collection := client.Database("test").Collection("users")
data := bson.M{
"name": "张三",
"age": 21,
}
result, err := collection.InsertOne(context.Background(), data)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(result.InsertedID)
}
func insert3() {
collection := client.Database("test").Collection("users")
type Info struct {
Name string `bson:"name1"`
Age int `bson:"age1"`
}
var info = Info{"王五", 12}
result, err := collection.InsertOne(context.Background(), info)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(result.InsertedID)
}
查询数据
package main
import (
"context"
"fmt"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo/options"
)
func main() {
find5()
}
func find1() {
collection := client.Database("test").Collection("users")
sr := collection.FindOne(context.Background(), bson.M{"name": "fengfeng"})
fmt.Println(sr.Raw())
var data bson.M
err := sr.Decode(&data)
fmt.Println(data, err)
type Info struct {
Name string
Age int
ID string `bson:"_id"`
}
var info Info
err = sr.Decode(&info)
fmt.Println(info, err)
}
func find2() {
collection := client.Database("test").Collection("users")
objectID, err := primitive.ObjectIDFromHex("68e9104e26aef638551098ab")
fmt.Println(objectID, err)
sr := collection.FindOne(context.Background(), bson.M{"_id": objectID})
fmt.Println(sr.Raw())
}
func find3() {
collection := client.Database("test").Collection("users")
cursor, err := collection.Find(context.Background(), bson.M{})
fmt.Println(cursor, err)
for cursor.Next(context.Background()) {
fmt.Println(cursor.Current.String())
}
}
func find4() {
collection := client.Database("test").Collection("users")
var limit int64 = 2
var skip int64 = 2
cursor, err := collection.Find(context.Background(), bson.M{}, &options.FindOptions{
Limit: &limit,
Skip: &skip,
})
fmt.Println(cursor, err)
for cursor.Next(context.Background()) {
fmt.Println(cursor.Current.String())
}
}
func find5() {
collection := client.Database("test").Collection("users")
cursor, err := collection.Find(context.Background(), bson.M{})
fmt.Println(cursor, err)
//var data bson.A
//err = cursor.All(context.Background(), &data)
//fmt.Println(data, err)
// 调了all之后,就没有了
type Info struct {
Name string
Age int
ID string `bson:"_id"`
}
var infoList []Info
err = cursor.All(context.Background(), &infoList)
fmt.Println(infoList, err)
}
删除数据
func remove1() {
collection := client.Database("test").Collection("users")
dr, err := collection.DeleteOne(context.Background(), bson.M{"name": "fengfeng"})
fmt.Println(dr.DeletedCount, err)
}
func remove2() {
collection := client.Database("test").Collection("users")
dr, err := collection.DeleteMany(context.Background(), bson.M{})
fmt.Println(dr.DeletedCount, err)
}
更新数据
func update1() {
collection := client.Database("db").Collection("user")
//c, err := collection.Find(context.Background(), bson.M{})
//var data bson.A
//err = c.All(context.Background(), &data)
//fmt.Println(data, err)
ur, err := collection.UpdateOne(context.Background(), bson.M{"name": "auth_0"}, bson.M{"$set": bson.M{"name": "auth_00"}})
fmt.Println(ur, err)
}
func update2() {
collection := client.Database("db").Collection("user")
//c, err := collection.Find(context.Background(), bson.M{})
//var data bson.A
//err = c.All(context.Background(), &data)
//fmt.Println(data, err)
objectID, _ := primitive.ObjectIDFromHex("68e8f4406f59126e045d8f92")
ur, err := collection.UpdateByID(context.Background(), objectID, bson.M{"$set": bson.M{"name": "auth_11"}})
fmt.Println(ur, err)
}
func update3() {
collection := client.Database("db").Collection("user")
ur, err := collection.UpdateMany(context.Background(), bson.M{
"index": bson.M{"$in": []int{1, 2, 3}},
}, bson.M{"$set": bson.M{"name": "000"}})
fmt.Println(ur, err)
c, _ := collection.Find(context.Background(), bson.M{
"index": bson.M{"$in": []int{1, 2, 3}},
})
var data bson.A
c.All(context.Background(), &data)
fmt.Println(data)
}
不同的bson类型
bson.D(有序文档)
字段顺序严格按照添加顺序存储和传输,查询时也会保持顺序。
适合需要精确控制字段顺序的场景(如 MongoDB 的聚合管道、排序规则等)。
bson.E(文档字段元素)
作为 bson.D 的组成单元,用于定义有序文档中的每个字段。
bson.M(无序文档)
语法更简洁,使用方式类似 JSON 对象,适合快速构建简单文档。
字段顺序在编码 / 解码时可能被打乱,不适合依赖顺序的场景。
bson.A(数组)
元素可以是任意类型(字符串、数字、bson.D、bson.M 甚至另一个 bson.A)。
保留元素的插入顺序,与 MongoDB 中的数组行为一致。
mongodb高级操作
索引
索引是一种排序好的便于快速查询数据的数据结构,用于帮助数据库高效的查询数据
优点:
- 提高数据查询的效率,降低数据库的IO成本
- 通过索引对数据进行排序,降低数据排序的成本,降低CPU的消耗
缺点:
- 占用磁盘空间
- 大量索引影响SQL语句的执行效率,因为每次插入和修改数据都要更新索引
// 创建索引 db.集合名.createIndex({待创建索引的列:方式} [,额外选项]) 1表示升序,-1表示降序
// 额外选项:设置索引的名称或者唯一索引等
// 设置名称:{name:索引名}
// 唯一索引:{unique:列名}
db.user.createIndex({name: 1})
// 查看索引
db.user.getIndexes()
// 删除全部索引
db.user.dropIndexes()
// 删除指定索引
db.user.dropIndex("name_1")
可以看到,加了索引之后,查询效率的提升是很明显的

权限机制
安装完Mongodb后,在命令行输入mongosh 命令即可登录数据库,这肯定是不安全的,我们需要使用权限机制,开启验证模式
创建账号
db.createUser({
"user":"账号",
"pwd":"密码",
"roles":[{
role:"角色",
db:"所属数据库"
}]
})
角色种类
超级用户角色:root
数据库用户角色:read、readWrite
数据库管理角色:dbAdmin、userAdmin
集群管理角色: clusterAdmin、clusterManager、clusterMonitor、hostManager
备份恢复角色: backup、restore
所有数据库角色: readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase
角色说明
root:只在admin数据库中可用。超级账号,超级权限;
read:允许用户读取指定数据库;
readWrite:允许用户读写指定数据库
db.createUser({
"user":"fengfeng",
"pwd":"1234",
"roles":[{
role:"read",
db:"test"
}]
})
// 查询当前库下的用户列表
db.getUsers()
// 删除用户
db.dropUser("fengfeng")
权限的用法
管理人员创建一个很复杂的root用户,基于这个root用户创建不同角色的用户,再把这些用户分配给不同人去使用mongo
数据导入导出
MongoDB 提供了专门的工具用于数据的导入导出,最常用的是 mongoexport(导出)和 mongoimport(导入),支持 JSON、CSV 等格式。
数据导出
mongoexport --uri="mongodb://用户名:密码@主机:端口/数据库名?authSource=认证数据库" \
--collection=集合名 \
--out=输出文件路径 \
[--type=格式] # 可选,默认json,支持csv
导出json
mongoexport --uri="mongodb://root:root@127.0.0.1:27017/test?authSource=admin" --collection=user --out=user.json --type=json
导出csv
mongoexport --uri="mongodb://root:root@localhost:27017/test?authSource=admin" --collection=user --type=csv --fields=name,age --out=./user.csv
带条件导出
mongoexport --uri="mongodb://root:root@localhost:27017/test?authSource=admin" --collection=user --query='{"age": {"$gt": 18}}' --out=./adult_user.json
数据导入
mongoimport 用于将 JSON/CSV 数据导入到集合
mongoimport --uri="mongodb://用户名:密码@主机:端口/数据库名?authSource=认证数据库" \
--collection=集合名 \
--file=输入文件路径 \
[--type=格式] # 可选,默认json,支持csv
[--headerline] # CSV格式时使用,第一行为字段名
导入json数据
mongoimport --uri="mongodb://root:root@localhost:27017/test?authSource=admin" --collection=user1 --file=./user.json
备份与恢复
如果需要完整备份数据库(包括索引、结构等),推荐使用 mongodump 和 mongorestore
# 备份整个数据库(生成二进制BSON文件)
mongodump --uri="mongodb://root:root@localhost:27017/?authSource=admin" --db=test --out=./backup
# 恢复test数据库
mongorestore --uri="mongodb://root:root@localhost:27017/?authSource=admin" --db=test ./backup/test
参考文档
MongoDB从零开始详细教程 https://blog.youkuaiyun.com/qq_45173404/article/details/114260970
go操作mongo https://blog.youkuaiyun.com/cui_yonghua/article/details/152553260
4万+

被折叠的 条评论
为什么被折叠?



