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 | 判断值是否不在一个数组中 |
多条件and、or查询示例如下:
# 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 }
>
更新
更新的方法有updateOne和updateMany两种方法,对应查询的两种方法是一样
第一个文档是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" }
>
删除
删除方法同上面基本一样,也是提供两个方法deleteOne和deleteMany, 过滤删除只需要在括号中写好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()
>

浙公网安备 33010602011771号