Go操作MongoDB 1 . 简介 mongoDB 是目前比较流行的一个基于分布式文件存储 的数据库 ,它是一个介于关系数据库和非关系数据库(NoSQL)之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。
2 . MongoDB介绍和部署 mongoDB 是目前比较流行的一个基于分布式文件存储的数据库,它是一个介于关系数据库和非关系数据库(NoSQL)之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。
mongoDB中将一条数据存储为一个文档(document),数据结构由键值(key-value)对组成。 其中文档类似于我们平常编程中用到的JSON对象。 文档中的字段值可以包含其他文档,数组及文档数组。
2.1 MongoDB相关概念 mongoDB中相关概念与我们熟悉的SQL概念对比如下:
MongoDB术语/概念 说明 对比SQL术语/概念 database 数据库 database collection 集合 table document 文档 row field 字段 column index index 索引 primary key 主键 MongoDB自动将_id字段设置为主键 primary key
2.2 MongoDB本地安装 我们这里下载和安装社区版,官网下载地址 。 打开上述连接后,选择对应的版本、操作系统平台(常见的平台均支持)和包类型,点击Download按钮下载即可。
这里补充说明下,Windows平台有ZIP和MSI两种包类型: * ZIP:压缩文件版本 * MSI:可执行文件版本,点击”下一步”安装即可。
macOS平台除了在该网页下载TGZ文件外,还可以使用Homebrew安装。
更多安装细节可以参考官方安装教程 ,里面有Linux、macOS和Windows三大主流平台的安装教程。
安装
# 创建mongo用户 useradd mongod echo 123 |passwd --stdin mongod # 创建目录结构 mkdir -p /mongodb/{conf,log,data,bin} # 解压软件到指定位置 tar xf mongodb-linux-x86_64-rhel70-3.4 .24 .tgz -C /mongodb/ cp -a /mongodb/mongodb-linux-x86_64-rhel70-3.4 .24 /bin
启动
mongod --dbpath=/opt/ data/apps/mongodb/data --logpath=/opt/ data/apps/mongodb/log/mongo.log --port=27017 --logappend --fork cat >> /etc/ security/limits.conf <<EOF * soft nproc 65530 * hard nproc 65530 * soft nofile 65530 * hard nofile 65530 EOF ulimit -n 65535 ulimit -u 20480 mongo
配置文件启动
[mongod@client-1 mongodb]$ cat /opt/data/apps/mongodb/conf/mongo.conf dbpath=/opt/ data/apps/mongodb/data logpath=/opt/ data/apps/mongodb/log/mongo.log logappend = true port=27017 fork=true auth=true #bind_ip = 127.0 .0 .1 journal=true quiet=true $ mongod -f /opt/data/apps/mongodb/conf/mongo.conf mongod -f /opt/data/apps/mongodb/conf/mongo.conf --shutdown cat > /etc/ systemd/system/mongod.service <<EOF [Unit] Description=mongodb After=network.target remote-fs.target nss-lookup.target [Service] User=mongod Type=forking ExecStart=/opt/ data/apps/mongodb/bin/mongod --config /opt/data/apps/mongodb/conf/mongo.conf ExecReload=/bin/ kill -s HUP $MAINPID ExecStop=/opt/ data/apps/mongodb/bin/mongod --config /opt/data/apps/mongodb/conf/mongo.conf --shutdown PrivateTmp=true [Install] WantedBy=multi-user.target EOF systemctl start mongod systemctl stop mongod systemctl restart mongod
2.3 Docker安装MongoDB 查看可用的 MongoDB 版本
$ docker search mongo NAME DESCRIPTION STARS OFFICIAL AUTOMATED mongo MongoDB document databases ... 1989 [OK] mongo-express Web-based MongoDB admin int... 22 [OK] mvertes/alpine-mongo light MongoDB container 19 [OK] mongooseim/mongooseim-docker MongooseIM server the lates... 9 [OK] torusware/speedus-mongo Always updated official Mon... 9 [OK] jacksoncage/mongo Instant MongoDB sharded cluster 6 [OK] mongoclient/mongoclient Official docker image for M... 4 [OK] jadsonlourenco/mongo-rocks Percona Mongodb with Rocksd... 4 [OK] asteris/apache-php-mongo Apache2.4 + PHP + Mongo + m... 2 [OK] 19hz/mongo-container Mongodb replicaset for coreos 1 [OK] nitra/mongo Mongo3 centos7 1 [OK] ackee/mongo MongoDB with fixed Bluemix p... 1 [OK] kobotoolbox/mongo https://github.com/kobotoolb... 1 [OK] valtlfelipe/mongo Docker Image based on the la... 1 [OK]
拉取最新版的 MongoDB 镜像
这里我们拉取官方的最新版本的镜像:
$ docker pull mongo:latest
查看本地镜像
使用以下命令来查看是否已安装了 mongo:
运行容器
安装完成后,我们可以使用以下命令来运行 mongo 容器:
$ docker run -itd --name mongo -p 27017:27017 mongo --auth
参数说明:
-p 27017:27017 :映射容器服务的 27017 端口到宿主机的 27017 端口。外部可以直接通过 宿主机 ip:27017 访问到 mongo 的服务。–auth :需要密码才能访问容器服务。安装成功
最后我们可以通过 docker ps 命令查看容器的运行信息
接着使用以下命令添加用户和设置密码,并且尝试连接。
$ docker exec -it mongo mongo admin > db.createUser({ user:'admin' ,pwd :'123456' ,roles:[ { role:'userAdminAnyDatabase' , db: 'admin' }]}); > db.auth('admin' , '123456' )
3 . MongoDB基本使用 3.1 启动MongoDB数据库 3.2 数据库常用命令 show dbs;:查看数据库 > show dbs; admin 0. 000GB config 0. 000GB local 0. 000GB > use youmen # 切换到指定数据库,如果不存在该数据库就创建。 switched to db youmen > db # 显示当前所在数据库。 youmen > db.dropDatabase() # 删除当前数据库 { "ok" : 1 }
3.3 数据集常用命令 db.createCollection(name,options):创建数据集 name:数据集名称 options:可选参数,指定内存大小和索引。 > db.createCollection("student" ); { "ok" : 1 } show collections;:查看当前数据库中所有集合。 > show collections; student db.student.drop():删除指定数据集 > db.student.drop() true
3.4 文档常用命令 插入一条文档
{ "acknowledged" : true , "insertedId" : ObjectId("613ee40f9462ebfb9de4f671" ) }
插入多条文档
> db.student.insertMany([ ... {name:"张三" ,age:20 }, ... {name:"李四" ,age:25 } ... ]); { "acknowledged" : true , "insertedIds" : [ ObjectId("613ee4349462ebfb9de4f672" ), ObjectId("613ee4349462ebfb9de4f673" ) ] }
查询所有文档
> db.student.find(); { "_id" : ObjectId("613ee40f9462ebfb9de4f671" ), "name" : "youmen" , "age" : 18 } { "_id" : ObjectId("613ee4349462ebfb9de4f672" ), "name" : "张三" , "age" : 20 } { "_id" : ObjectId("613ee4349462ebfb9de4f673" ), "name" : "李四" , "age" : 25 }
查询age>20岁的文档
> db.student.find( ... {age:{$gt:20 }} ... ) { "_id" : ObjectId("613ee4349462ebfb9de4f673" ), "name" : "李四" , "age" : 25 }
更新文档
> db.student.update( ... {name:"youmen" }, ... {name:"wunai" ,age:21 } ... ); WriteResult({ "nMatched" : 1 , "nUpserted" : 0 , "nModified" : 1 }) > db.student.find() { "_id" : ObjectId("613ee40f9462ebfb9de4f671" ), "name" : "wunai" , "age" : 21 } { "_id" : ObjectId("613ee4349462ebfb9de4f672" ), "name" : "张三" , "age" : 20 } { "_id" : ObjectId("613ee4349462ebfb9de4f673" ), "name" : "李四" , "age" : 25 }
删除文档
> db.student.deleteOne({name:"李四" }); { "acknowledged" : true , "deletedCount" : 1 } > db.student.find() { "_id" : ObjectId("613ee40f9462ebfb9de4f671" ), "name" : "wunai" , "age" : 21 } { "_id" : ObjectId("613ee4349462ebfb9de4f672" ), "name" : "张三" , "age" : 20 }
命令实在太多,更多命令请参阅官方文档:shell命令 和官方文档:CRUD操作 。
4. Go操作MongoDB 4.1 通过Golang连接MongoDB package mainimport ( "context" "fmt" "log" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) func main () { clientOptions := options.Client().ApplyURI("mongodb://1.1.1.1:27017" ) 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!" ) }
如果设置了auth认证,则需要添加认证信息
package mainimport ( "context" "fmt" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) func main () { var ( err error client *mongo.Client database *mongo.Database collection *mongo.Collection ) clientOptions := options.Client().ApplyURI("mongodb://127.0.0.1:27017" ) client, err = mongo.Connect(context.TODO(), clientOptions) if err != nil { fmt.Println("连接失败!" ) } err = client.Ping(context.TODO(), nil ) if err != nil { fmt.Println("ping 失败" ) } database = client.Database("my_db" ) collection = database.Collection("my_collection" ) fmt.Println(collection.Name()) }
连接上MongoDB之后,可以通过下面的语句处理我们上面的youmen数据库中的student数据集了:
package mainimport ( "context" "fmt" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "log" ) func main () { clientOptions := options.Client().ApplyURI("mongodb://1.1.1.1:27017" ) 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!" ) connection := client.Database("youmen" ).Collection("student" ) fmt.Println(connection) err = client.Disconnect(context.TODO()) if err != nil { log.Fatal(err) } fmt.Println("Connection to MongoDB closed." ) }
4.2 连接池模式 package mainimport ( "context" "fmt" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "log" "time" ) func ConnectToDB (uri string ,name string ,timeout time.Duration,num uint64 ) (*mongo.Database,error) { ctx,cancel := context.WithTimeout(context.Background(),timeout) defer cancel() o := options.Client().ApplyURI(uri) o.SetMaxPoolSize(num) client,err := mongo.Connect(ctx,o) if err != nil { return nil ,err } return client.Database(name),nil } var num uint64 func main () { num=20 clientOptions,err := ConnectToDB("mongodb://1.1.1.1:27017" ,"youmen" , time.Duration(num),20 ) fmt.Println(clientOptions) if err != nil { log.Fatal(err) } err = clientOptions.Client().Ping(context.TODO(), nil ) if err != nil { log.Fatal(err) } fmt.Println("Connected to MongoDB!" ) connection := clientOptions.Client().Database("youmen" ).Collection("student" ) fmt.Println(connection) err = clientOptions.Client().Disconnect(context.TODO()) if err != nil { log.Fatal(err) } fmt.Println("Connection to MongoDB closed." ) }
5. BSON MongoDB中的JSON文档存储在名为BSON(二进制编码的JSON)的二进制表示中。与其他将JSON数据存储为简单字符串和数字的数据库不同,BSON编码扩展了JSON表示,使其包含额外的类型,如int、long、date、浮点数和decimal128。这使得应用程序更容易可靠地处理、排序和比较数据。
连接MongoDB的Go驱动程序中有两大类型表示BSON数据:D和Raw。
类型D家族被用来简洁地构建使用本地Go类型的BSON对象。这对于构造传递给MongoDB的命令特别有用。D家族包括四类:
D: 一个BSON文档。这种类型应该在顺序重要的情况下使用,比如MongoDB命令。
M: 一张无序的map。它和D是一样的,只是它不保持顺序。
A: 一个BSON数组。
E: D里面的一个元素。
要使用BSON,需要先导入下面包:
import "go.mongodb.org/mongo-driver/bson"
下面是一个使用D类型构建的过滤器文档的例子,它可以用来查找name字段与’张三’或’李四’匹配的文档:
bson.D{{ "name" , bson.D{{ "$in" , bson.A{"张三" , "李四" }, }}, }}
Raw类型家族用于验证字节切片。你还可以使用Lookup()从原始类型检索单个元素。如果你不想要将BSON反序列化成另一种类型的开销,那么这是非常有用的。这个教程我们将只使用D类型。
5.1 CURD 我们先在Go代码定义一个Student类型如下:
type Student struct { Name string Age int }
接下来,创建一些Student类型值,准备插入到数据库中:
s1 := Student{"小红" , 12 } s2 := Student{"小兰" , 10 } s3 := Student{"小黄" , 11 }
插入文档
使用collection.InsertOne()方法插入一条文档记录:
insertResult, err := collection.InsertOne(context.TODO(), s1) if err != nil { log.Fatal(err) } fmt.Println("Inserted a single document: " , insertResult.InsertedID)
使用collection.InsertMany()方法插入多条文档记录:
students := []interface {}{s2, s3} insertManyResult, err := collection.InsertMany(context.TODO(), students) if err != nil { log.Fatal(err) } fmt.Println("Inserted multiple documents: " , insertManyResult.InsertedIDs)
更新文档
updateone()方法允许你更新单个文档。它需要一个筛选器文档来匹配数据库中的文档,并需要一个更新文档来描述更新操作。你可以使用bson.D类型来构建筛选文档和更新文档:
filter := bson.D{{"name" , "小兰" }} update := bson.D{ {"$inc" , bson.D{ {"age" , 1 }, }}, }
接下来,就可以通过下面语句找到小兰,给他增加一岁了;
updateResult, err := collection.UpdateOne(context.TODO(), filter, update) if err != nil { log.Fatal(err) } fmt.Printf("Matched %v documents and updated %v documents.\n" , updateResult.MatchedCount, updateResult.ModifiedCount)
查找文档
要找到一个文档,你需要一个filter文档,以及一个指向可以将结果解码为其值的指针。要查找单个文档,使用collection.FindOne()。这个方法返回一个可以解码为值的结果。
我们使用上面定义过的那个filter来查找姓名为’小兰’的文档。
var result Studenterr = collection.FindOne(context.TODO(), filter).Decode(&result) if err != nil { log.Fatal(err) } fmt.Printf("Found a single document: %+v\n" , result)
要查找多个文档,请使用collection.Find()。此方法返回一个游标。游标提供了一个文档流,你可以通过它一次迭代和解码一个文档。当游标用完之后,应该关闭游标。下面的示例将使用options包设置一个限制以便只返回两个文档。
findOptions := options.Find() findOptions.SetLimit(2 ) var results []*Studentcur, err := collection.Find(context.TODO(), bson.D{{}}, findOptions) if err != nil { log.Fatal(err) } for cur.Next(context.TODO()) { var elem Student err := cur.Decode(&elem) if err != nil { log.Fatal(err) } results = append (results, &elem) } if err := cur.Err(); err != nil { log.Fatal(err) } cur.Close(context.TODO()) fmt.Printf("Found multiple documents (array of pointers): %#v\n" , results)
删除文档
最后,可以使用collection.DeleteOne()或collection.DeleteMany()删除文档。如果你传递bson.D{{}}
作为过滤器参数,它将匹配数据集中的所有文档。还可以使用collection. drop()删除整个数据集。
deleteResult1, err := collection.DeleteOne(context.TODO(), bson.D{{"name" ,"小黄" }}) if err != nil { log.Fatal(err) } fmt.Printf("Deleted %v documents in the trainers collection\n" , deleteResult1.DeletedCount) deleteResult2, err := collection.DeleteMany(context.TODO(), bson.D{{}}) if err != nil { log.Fatal(err) } fmt.Printf("Deleted %v documents in the trainers collection\n" , deleteResult2.DeletedCount) package mainimport ( "fmt" "reflect" ) type person struct { name string age int } func main () { v := reflect.ValueOf(person{"steve" , 30 }) count := v.NumField() for i := 0 ; i < count; i++ { f := v.Field(i) switch f.Kind() { case reflect.String: fmt.Println(f.String()) case reflect.Int: fmt.Println(f.Int()) } } }
5.2 获取Mongo服务状态 ctx, _ = context.WithTimeout(context.Background(), 30 *time.Second) serverStatus, err := client.Database("admin" ).RunCommand( ctx, bsonx.Doc{{"serverStatus" , bsonx.Int32(1 )}}, ).DecodeBytes() if err != nil { fmt.Println(err) } fmt.Println(serverStatus) fmt.Println(reflect.TypeOf(serverStatus)) version, err := serverStatus.LookupErr("version" ) fmt.Println(version.StringValue()) if err != nil { fmt.Println(err) }
参考链接Go操作MongoDB - 云+社区 - 腾讯云 (tencent.com) MongoDB 删除数据库 | 菜鸟教程 (runoob.com)