MongoDB

一直没整理过 MongoDB 的笔记,这次开个文档记录下
MongoDB 不同于关系型数据库,使用来描述数据,而是采用集合来描述数据, 关系型数据库中表里面就是数据,MongoDB的集合中也是存放数据的,不过在这里称之为文档

安装

docker 直接启动服务,并设置持久化

docker run -d --name mongo-server \
-p 27017:27017 \
-v /data/mongo/db:/data/db \
-v /data/mongo/configdb:/data/configdb \
mongo

数据库角色

  • 数据库用户角色(Database User Roles):
    • read:授予User只读数据的权限
    • readWrite:授予User读写数据的权限
  • 数据库管理角色(Database Administration Roles):
    • dbAdmin:在当前dB中执行管理操作
    • dbOwner:在当前DB中执行任意操作
    • userAdmin:在当前DB中管理User
  • 备份和还原角色(Backup and Restoration Roles):
    • backup
    • restore
  • 跨库角色(All-Database Roles):
    • readAnyDatabase:授予在所有数据库上读取数据的权限
    • readWriteAnyDatabase:授予在所有数据库上读写数据的权限
    • userAdminAnyDatabase:授予在所有数据库上管理User的权限
    • dbAdminAnyDatabase:授予管理所有数据库的权限
  • 集群管理角色(Cluster Administration Roles):
    • clusterAdmin:授予管理集群的最高权限
    • clusterManager:授予管理和监控集群的权限,A user with this role can access the config and local databases, which are used in sharding and replication, respectively.
    • clusterMonitor:授予监控集群的权限,对监控工具具有readonly的权限
    • hostManager:管理Server

建立数据库

建立数据库并创建数据库的管理用户

(~) >>> docker exec -it mongo-server bash
root@f08c332ceaae:/#
root@f08c332ceaae:/# mongo admin

...
..
.

> show dbs;
admin   0.000GB
config  0.000GB
local   0.000GB
> use novel;
switched to db novel
> db.createUser({user: 'novel', pwd: '123456', roles: [{role: 'dbOwner', db:'novel'}]});
Successfully added user: {
	"user" : "novel",
	"roles" : [
		{
			"role" : "dbOwner",
			"db" : "novel"
		}
	]
}
>
> db.auth('novel', '123456');
1
>

操作

MongoDB 的 CRUD 操作, 操作方法全都在 MongoDB 的 shell 中操作

插入

官网提供了三种方法全都用于插入数据, 向不存在的collection插入数据则MongoDB会自动新建collection

  • db.collection.insertOne()
  • db.collection.insertMany()
  • db.collection.insert()

使用示例:

insert方法可以同时支持单条多条插入操作, 插入单条传入一个document即可,插入多条则传入一个document array

# insertOne
> db.sanshiyi.insertOne({name:"one", age:30, status: 5})
{
	"acknowledged" : true,
	"insertedId" : ObjectId("603318a2afd636648a160d0a")
}
>

# insertMany
> db.sanshiyi.insertMany([{name:"zhangsan", age:27, status: 1}, {name:"wangwu", age:28, status: 0}]);
{
	"acknowledged" : true,
	"insertedIds" : [
		ObjectId("603317aeafd636648a160d06"),
		ObjectId("603317aeafd636648a160d07")
	]
}
>

# insert 
> db.sanshiyi.insert({name:"insert-test", age: 30, status:6})
WriteResult({ "nInserted" : 1 })
> db.sanshiyi.insert([{name:"insert-test3", age: 30, status:6}, {name:"insert-test2", age: 30, status:6}])
BulkWriteResult({
	"writeErrors" : [ ],
	"writeConcernErrors" : [ ],
	"nInserted" : 2,
	"nUpserted" : 0,
	"nMatched" : 0,
	"nModified" : 0,
	"nRemoved" : 0,
	"upserted" : [ ]
})
>

查找

查询文档使用db.collection.find()方法, 过滤查询直接在find的括号中写一个条件字段的document,比如下面的示例,查询所有数据,和简单的过滤单条件查询

# 查询全部数据
> db.sanshiyi.find()
{ "_id" : ObjectId("60331501afd636648a160d04"), "name" : "wangyong", "age" : 27, "status" : 1 }
{ "_id" : ObjectId("60331501afd636648a160d05"), "name" : "lisi", "age" : 28, "status" : 0 }
{ "_id" : ObjectId("603317aeafd636648a160d06"), "name" : "zhangsan", "age" : 27, "status" : 1 }
{ "_id" : ObjectId("603317aeafd636648a160d07"), "name" : "wangwu", "age" : 28, "status" : 0 }
{ "_id" : ObjectId("603317ccafd636648a160d08"), "name" : "sana", "age" : 27, "status" : 3 }
{ "_id" : ObjectId("603317ccafd636648a160d09"), "name" : "tea", "age" : 28, "status" : 2 }
{ "_id" : ObjectId("603318a2afd636648a160d0a"), "name" : "one", "age" : 30, "status" : 5 }
{ "_id" : ObjectId("6033214f9932a75b936ab0c8"), "name" : "insert-test", "age" : 30, "status" : 6 }
{ "_id" : ObjectId("603321659932a75b936ab0c9"), "name" : "insert-test3", "age" : 30, "status" : 6 }
{ "_id" : ObjectId("603321659932a75b936ab0ca"), "name" : "insert-test2", "age" : 30, "status" : 6 }
>
# 单条件查询
> db.sanshiyi.find({status: 1})
{ "_id" : ObjectId("60331501afd636648a160d04"), "name" : "wangyong", "age" : 27, "status" : 1 }
{ "_id" : ObjectId("603317aeafd636648a160d06"), "name" : "zhangsan", "age" : 27, "status" : 1 }
>

多条件查询其实只是在文档中写多个过滤字段,字段之间是一个and关系, 某个字段的值进行大于等于小于等判断参考下面的操作符列表

名称 描述
$eq 判断值相等
$gt 判断值大于
$gte 判断值大于等于
$in 判断值是否一个数组中
$lt 判断值小于
$lte 判断值小于等于
$ne 判断值不等于
$nin 判断值是否不在一个数组中

多条件andor查询示例如下:

# or 查询, 查询 name 为 wangyong 或者 age 小于 28 的数据
> db.sanshiyi.find({$or: [{name: "wangyong"}, {age: {$lt: 28}}]})
{ "_id" : ObjectId("60331501afd636648a160d04"), "name" : "wangyong", "age" : 27, "status" : 1 }
{ "_id" : ObjectId("603317aeafd636648a160d06"), "name" : "zhangsan", "age" : 27, "status" : 1 }
{ "_id" : ObjectId("603317ccafd636648a160d08"), "name" : "sana", "age" : 27, "status" : 3 }
> 
# or 和 and 联合查询, 查询 name 为 wangyong 或者 age 等于27 并且 status 等于 3 的数据
> db.sanshiyi.find({$or:[{name:"wangyong"}, {$and:[{age: 27}, {status: 3}]}]})
{ "_id" : ObjectId("60331501afd636648a160d04"), "name" : "wangyong", "age" : 27, "status" : 1 }
{ "_id" : ObjectId("603317ccafd636648a160d08"), "name" : "sana", "age" : 27, "status" : 3 }
>

MongoDB还有个findOne方法,此方法只返回一个查询结果,内部就是调用find方法查询,结果限制为1, 返回值为一个文档, 如下示例:

> db.sanshiyi.findOne({$or:[{name:"wangyong"}, {$and:[{age: 27}, {status: 3}]}]})
{
	"_id" : ObjectId("60331501afd636648a160d04"),
	"name" : "wangyong",
	"age" : 27,
	"status" : 1
}
>

我们可以直接在mongo shell中保存查询结果的游标然后进一步干别的操作, 还可以通过游标索引获取其中的一条数据

# 循环结果,以json形式打印出结果
> var result = db.sanshiyi.find({$or:[{name:"wangyong"}, {$and:[{age: 27}, {status: 3}]}]});
> while (result.hasNext()) { printjson(result.next()); }
{
	"_id" : ObjectId("60331501afd636648a160d04"),
	"name" : "wangyong",
	"age" : 27,
	"status" : 1
}
{
	"_id" : ObjectId("603317ccafd636648a160d08"),
	"name" : "sana",
	"age" : 27,
	"status" : 3
}
>

# 使用游标获取其中一条数据
> var result = db.sanshiyi.find({$or:[{name:"wangyong"}, {$and:[{age: 27}, {status: 3}]}]});
>
> printjson(result[1]);
{
	"_id" : ObjectId("603317ccafd636648a160d08"),
	"name" : "sana",
	"age" : 27,
	"status" : 3
}
>

筛选查询结果字段, 除_id字段外不能在文档中合并包含排除, 意思就是如果文档中已经有字段被设置为1 则,未写入文档的字段不会显示, 反之, 值设置为0未写入文档的字段将会显示

# 选择 name 和 age 字段 去除 _id 字段返回
> db.sanshiyi.find({$or:[{name:"wangyong"}, {$and:[{age: 27}, {status: 3}]}]}, {name:1, age: 1, _id: 0});
{ "name" : "wangyong", "age" : 27 }
{ "name" : "sana", "age" : 27 }
>

更新

更新的方法有updateOneupdateMany两种方法,对应查询的两种方法是一样

第一个文档是filter过滤字段条件,第二个字段使用$set来设置对应的属性

# 查询数据
> db.s2.find()
{ "_id" : ObjectId("603711ec85713b74a5b8eff3"), "name" : "sw1", "age" : 1, "status" : 1, "isopen" : false }
{ "_id" : ObjectId("603711ec85713b74a5b8eff4"), "name" : "w1", "age" : 1, "status" : 1, "isopen" : false }
{ "_id" : ObjectId("603711ec85713b74a5b8eff5"), "name" : "w2", "age" : 2, "status" : 2, "isopen" : true }
{ "_id" : ObjectId("603711ec85713b74a5b8eff6"), "name" : "w3", "age" : 3, "status" : 1, "isopen" : false }
{ "_id" : ObjectId("60371326b1d12a84144f6058"), "name" : "sw1", "age" : 1, "status" : 1, "is_open" : false }
{ "_id" : ObjectId("60371326b1d12a84144f6059"), "name" : "w1", "age" : 1, "status" : 1, "is_open" : false }
{ "_id" : ObjectId("60371326b1d12a84144f605a"), "name" : "w2", "age" : 2, "status" : 2, "is_open" : true }
{ "_id" : ObjectId("60371326b1d12a84144f605b"), "name" : "w3", "age" : 3, "status" : 1, "is_open" : false }
>
# 更新一条
> db.s2.updateOne({name:"w1"}, {$set:{name:"w11"}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.s2.find()
{ "_id" : ObjectId("603711ec85713b74a5b8eff3"), "name" : "sw1", "age" : 1, "status" : 1, "isopen" : false }
{ "_id" : ObjectId("603711ec85713b74a5b8eff4"), "name" : "w11", "age" : 1, "status" : 1, "isopen" : false }
{ "_id" : ObjectId("603711ec85713b74a5b8eff5"), "name" : "w2", "age" : 2, "status" : 2, "isopen" : true }
{ "_id" : ObjectId("603711ec85713b74a5b8eff6"), "name" : "w3", "age" : 3, "status" : 1, "isopen" : false }
{ "_id" : ObjectId("60371326b1d12a84144f6058"), "name" : "sw1", "age" : 1, "status" : 1, "is_open" : false }
{ "_id" : ObjectId("60371326b1d12a84144f6059"), "name" : "w1", "age" : 1, "status" : 1, "is_open" : false }
{ "_id" : ObjectId("60371326b1d12a84144f605a"), "name" : "w2", "age" : 2, "status" : 2, "is_open" : true }
{ "_id" : ObjectId("60371326b1d12a84144f605b"), "name" : "w3", "age" : 3, "status" : 1, "is_open" : false }

# 更新多条
> db.s2.updateMany({name:"w2"}, {$set: {name: "w22"}})
{ "acknowledged" : true, "matchedCount" : 2, "modifiedCount" : 2 }
>
> db.s2.find()
{ "_id" : ObjectId("603711ec85713b74a5b8eff3"), "name" : "sw1", "age" : 1, "status" : 1, "isopen" : false }
{ "_id" : ObjectId("603711ec85713b74a5b8eff4"), "name" : "w11", "age" : 1, "status" : 1, "isopen" : false }
{ "_id" : ObjectId("603711ec85713b74a5b8eff5"), "name" : "w22", "age" : 2, "status" : 2, "isopen" : true }
{ "_id" : ObjectId("603711ec85713b74a5b8eff6"), "name" : "w3", "age" : 3, "status" : 1, "isopen" : false }
{ "_id" : ObjectId("60371326b1d12a84144f6058"), "name" : "sw1", "age" : 1, "status" : 1, "is_open" : false }
{ "_id" : ObjectId("60371326b1d12a84144f6059"), "name" : "w1", "age" : 1, "status" : 1, "is_open" : false }
{ "_id" : ObjectId("60371326b1d12a84144f605a"), "name" : "w22", "age" : 2, "status" : 2, "is_open" : true }
{ "_id" : ObjectId("60371326b1d12a84144f605b"), "name" : "w3", "age" : 3, "status" : 1, "is_open" : false }
>

还支持直接更换模板, 使用replaceOne方法, 第一个参数还是filter文档, 第二个参数为全新的文档.

当替换一个文档时,替换文档必须只包含字段/值对;即不包括更新操作符表达式。

替换文档可以具有与原始文档不同的字段。在替换文档中,由于_id字段是不可变的,因此可以省略_id字段。但是,如果您确实包含_id字段,则它必须与当前值具有相同的值。

> db.s2.find()
{ "_id" : ObjectId("603711ec85713b74a5b8eff3"), "name" : "sw1", "age" : 1, "status" : 1, "isopen" : false }
{ "_id" : ObjectId("603711ec85713b74a5b8eff4"), "name" : "w11", "age" : 1, "status" : 1, "isopen" : false }
{ "_id" : ObjectId("603711ec85713b74a5b8eff5"), "name" : "w22", "age" : 2, "status" : 2, "isopen" : true }
{ "_id" : ObjectId("603711ec85713b74a5b8eff6"), "name" : "w3", "age" : 3, "status" : 1, "isopen" : false }
{ "_id" : ObjectId("60371326b1d12a84144f6058"), "name" : "sw1", "age" : 1, "status" : 1, "is_open" : false }
{ "_id" : ObjectId("60371326b1d12a84144f6059"), "name" : "w1", "age" : 1, "status" : 1, "is_open" : false }
{ "_id" : ObjectId("60371326b1d12a84144f605a"), "name" : "w22", "age" : 2, "status" : 2, "is_open" : true }
{ "_id" : ObjectId("60371326b1d12a84144f605b"), "name" : "w3", "age" : 3, "status" : 1, "is_open" : false }
>
>
>
> db.s2.replaceOne({name:"w3"}, {name:"op"})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
>
> db.s2.find()
{ "_id" : ObjectId("603711ec85713b74a5b8eff3"), "name" : "sw1", "age" : 1, "status" : 1, "isopen" : false }
{ "_id" : ObjectId("603711ec85713b74a5b8eff4"), "name" : "w11", "age" : 1, "status" : 1, "isopen" : false }
{ "_id" : ObjectId("603711ec85713b74a5b8eff5"), "name" : "w22", "age" : 2, "status" : 2, "isopen" : true }
{ "_id" : ObjectId("603711ec85713b74a5b8eff6"), "name" : "op" }
{ "_id" : ObjectId("60371326b1d12a84144f6058"), "name" : "sw1", "age" : 1, "status" : 1, "is_open" : false }
{ "_id" : ObjectId("60371326b1d12a84144f6059"), "name" : "w1", "age" : 1, "status" : 1, "is_open" : false }
{ "_id" : ObjectId("60371326b1d12a84144f605a"), "name" : "w22", "age" : 2, "status" : 2, "is_open" : true }
{ "_id" : ObjectId("60371326b1d12a84144f605b"), "name" : "w3", "age" : 3, "status" : 1, "is_open" : false }
>

如果上面的方法包含upsert:true参数,那么当更新一个不存在的文档时,会插入一个新的文档

> db.s2.replaceOne({name:"w4"}, {name:"o222p"}, {upsert:true})
{
	"acknowledged" : true,
	"matchedCount" : 0,
	"modifiedCount" : 0,
	"upsertedId" : ObjectId("60371a742eefd3803b78635b")
}
>
>
> db.s2.find()
{ "_id" : ObjectId("603711ec85713b74a5b8eff3"), "name" : "sw1", "age" : 1, "status" : 1, "isopen" : false }
{ "_id" : ObjectId("603711ec85713b74a5b8eff4"), "name" : "w11", "age" : 1, "status" : 1, "isopen" : false }
{ "_id" : ObjectId("603711ec85713b74a5b8eff5"), "name" : "w22", "age" : 2, "status" : 2, "isopen" : true }
{ "_id" : ObjectId("603711ec85713b74a5b8eff6"), "name" : "op" }
{ "_id" : ObjectId("60371326b1d12a84144f6058"), "name" : "sw1", "age" : 1, "status" : 1, "is_open" : false }
{ "_id" : ObjectId("60371326b1d12a84144f6059"), "name" : "w1", "age" : 1, "status" : 1, "is_open" : false }
{ "_id" : ObjectId("60371326b1d12a84144f605a"), "name" : "w22", "age" : 2, "status" : 2, "is_open" : true }
{ "_id" : ObjectId("60371326b1d12a84144f605b"), "name" : "w3", "age" : 3, "status" : 1, "is_open" : false }
{ "_id" : ObjectId("60371a742eefd3803b78635b"), "name" : "o222p" }
>

删除

删除方法同上面基本一样,也是提供两个方法deleteOnedeleteMany, 过滤删除只需要在括号中写好filter过滤数据即可, 删除所有文档传入一个空的filter即可

# 删除 name 为 sw22 的数据,多条时仅删除一条
> db.s2.deleteOne({name:"sw22"})
{ "acknowledged" : true, "deletedCount" : 1 }
> db.s2.find()
{ "_id" : ObjectId("603711ec85713b74a5b8eff3"), "name" : "sw11", "age" : 1, "status" : 1, "isopen" : false }
{ "_id" : ObjectId("603711ec85713b74a5b8eff4"), "name" : "w11", "age" : 1, "status" : 1, "isopen" : false }
{ "_id" : ObjectId("603711ec85713b74a5b8eff5"), "name" : "w22", "age" : 100, "status" : 2, "isopen" : true }
{ "_id" : ObjectId("603711ec85713b74a5b8eff6"), "name" : "op" }
{ "_id" : ObjectId("60371326b1d12a84144f6058"), "name" : "sw11", "age" : 1, "status" : 1, "is_open" : false }
{ "_id" : ObjectId("60371326b1d12a84144f6059"), "name" : "w1", "age" : 1, "status" : 1, "is_open" : false }
{ "_id" : ObjectId("60371326b1d12a84144f605a"), "name" : "w22", "age" : 100, "status" : 2, "is_open" : true }
{ "_id" : ObjectId("60371326b1d12a84144f605b"), "name" : "w3", "age" : 3, "status" : 1, "is_open" : false }
{ "_id" : ObjectId("60371a742eefd3803b78635b"), "name" : "o222p" }
{ "_id" : ObjectId("6037311a2eefd3803b786395"), "name" : "sw22" }
# 删除所有 name 为 w22 的数据
> db.s2.deleteMany({name: "w22"})
{ "acknowledged" : true, "deletedCount" : 2 }
>
> db.s2.find()
{ "_id" : ObjectId("603711ec85713b74a5b8eff3"), "name" : "sw11", "age" : 1, "status" : 1, "isopen" : false }
{ "_id" : ObjectId("603711ec85713b74a5b8eff4"), "name" : "w11", "age" : 1, "status" : 1, "isopen" : false }
{ "_id" : ObjectId("603711ec85713b74a5b8eff6"), "name" : "op" }
{ "_id" : ObjectId("60371326b1d12a84144f6058"), "name" : "sw11", "age" : 1, "status" : 1, "is_open" : false }
{ "_id" : ObjectId("60371326b1d12a84144f6059"), "name" : "w1", "age" : 1, "status" : 1, "is_open" : false }
{ "_id" : ObjectId("60371326b1d12a84144f605b"), "name" : "w3", "age" : 3, "status" : 1, "is_open" : false }
{ "_id" : ObjectId("60371a742eefd3803b78635b"), "name" : "o222p" }
{ "_id" : ObjectId("6037311a2eefd3803b786395"), "name" : "sw22" }
>
>
# 删除集合内的所有数据
> db.s2.deleteMany({})
{ "acknowledged" : true, "deletedCount" : 8 }
> db.s2.find()
>
posted @ 2021-04-06 09:08  shiersan  阅读(62)  评论(0)    收藏  举报