I. install mongodb
# docker
docker pull mongo:4 # install mongodb 4
docker images # show images
docker run --name mymongo -v /usr/local/var/docker/mongodb/data:/data/db -d mongo:4
docker ps
docker logs mymongo
# install mongo express
docker pull mongo-express
docker run --link mymongo:mongo -p 8081:8081 mongo-express
# mac
brew install mongodb-community
brew services start mongodb/brew/mongodb-community
#
1.1 init mongodb
set auth for mongodb
You can login mongodb direct without password when your mongodb version grate or enquit v4.2, BTW, if you want to active authorization, may try this conf:
cat >> /usr/local/etc/mongod.conf <<"EOF"
#配置文件开启强制验证
security:
authorization: "enabled"
EOF
mongo
> show dbs
> use admin
> db.createUser({
user: 'admin', // 用户名
pwd: '123456', // 密码
roles:[{
role: 'root', // 角色
db: 'admin' // 数据库
}]
})
> exit
brew services restart mongodb/brew/mongodb-community
mongo admin -u admin -p 123456
II. mongodb shell 操作
# 开启一个mongo shell 进程:
docker exec -it mymongo mongo
print('hello');
exit
III MongoDB操作之 CRUD
文档主键 _id
-
文档主键的唯一性
-
支持所有数据类型(数组除外)
-
复合主键
-
默认的文档主键
-
可以快速生成的12字节id
-
包含创建时间
创建文档:
db.collection.insert()
db.collection.save()
模拟实操:
insertOne 写入单个文档
use test
db.acc.insertOne({'_id':'acc1', 'name': 'aaa', 'age': 20})
# 第二次插入同个id会报错误
db.acc.insertOne({'_id':'acc1', 'name': 'aaa', 'age': 20})
# 发挥错误结果本身
try{
db.acc.insertOne({'_id':'acc1', 'name': 'aaa', 'age': 20})
} catch(e) {
print(e)
}
#如果想自动生成_id, 省略创建文档中的_id字段
insertMany 写入多个文档
创建多个文档 insertMany,
语法:
db.collection.insertMany()
db.<collection>.insertMany(
[<document1>,<document2>,...],
{
writeConcern:<document>,
ordered: <boolean> 路效6226
}
)
ordered参数用来决定 mongoDB是否要按顺序来写入这些文档如果 将 ordered参数设置为 false,mongoDB可以打乱文档写入的顺序,以便优化写入操作的性能,默认true 在顺序写入时,一旦遇到错误,操作便会退出,剩余的文档无论正确与否,都不会被写入
db.collection.insert() 创建单个或多个文档
db.<collection>.insert(
<document or array of documents>,
{
writeconcern:<document>,
ordered:<boolean>
}
)
insertone, insertMany和 insert的区别
- insertone和 insertMany命令不支持db.collection.explain()命令
- insert支持 db.collection.explain()命令
另一个可以用来创建文档的命令 save
db.collection. save()
db.<collection>.save(
<document>,
{
writeConcern:<document>
}
)
查询
-
db.collenction.find()
- db.collenction.find().pretty() # 美化打印
-
筛选文档:
比较操作符
{ <field>:{ $<operator>:<value> }}
$eq 匹配字段值相等的文档 $ne 匹配字段值不等的文档 收编92687 $gt 匹配字段值大于查询值的文档 $gte 匹配字段值大于或等于查询值的文档 $lt 匹配字段值小于查询值的文档 $lte 匹配字段值小于或等于查询值的文档
$in 匹配字段值与任一查询值相等的文档 $nin 匹配字段值与任何查询值都不等的文档
db.acc.find({name:{$eq: "alice"} })
db.accounts.find( { name: { $in: [ "alice" "charlie" ] } })
# $nin 也会筛选出并不包含查询字段的文档
逻辑操作符
$not 匹配筛选条件不成立的文档 $and 匹配多个筛选条件全部成立的文档 $or 匹配至少一个筛选条件成立的文档 $nor 匹配多个筛选条件全部不成立的文档
db.accounts.find( balance: { $not: { $1t: 500 } })
字段操作符
$exists 匹配包含查询字段的文档 $type 匹配字段类型符合查询值的文档
db. accounts.find( { { “_id.type":{ $exists: true }})
db. accounts.find( { "id.type":[ $ne: "checking", $exists: true } })
$type :
{field:{ $type: } } {field:{ $type: [ ,<BSON type2>,…]}}
# 读取文档主键是字符串的银行账户文档"
> db.accounts.find(+ id: $type:"string" }})
{"id":"account1","name":"alice","balance": 100 }
# 读取文档主键是对象主键或者是复合主键的银行账户文档"
> db. accounts. find( { _id: { $type: L"objectId", "object "] } } )
# 读取用户姓名是nul1的银行账户文档"
> db.accounts.find( { name: { $type: "null" ] })
# 也可以使用对应的BSON类型序号作为$type操作符的参数
> db.accounts.find( { id:{ $type: 2}})
{"id" accountl' 'name" 'alice" "balance" 100 }
数组操作符
$a11 匹配数组字段中包含所有查询值的文档 $elemMatch 匹配数组字段中至少存在一个值满足筛选条件的文档
{ :{ $all: [ , … ] }
创建包含数组和嵌套数组的文档
> db.accounts.insert ([
{
name: "jack",
balance: 2000,
contact: [ "11111111", "Alabama" "US" ]
},
{
name: "karen",
balance: 2500,
contact: [ ["22222222","33333333"],"Beiiing", 'China']
}
])
> db.accounts.find( { contact: { $all : ["China", "Beijing"] } } )
> db.accounts. find( { contact: { $elemMatch:{ $gt:"10000000", $1t: "20000000"
# 将$a11与 $elemMatch结合在一起使用
# 读取包含一个在10000000至20000000之间,和一个在20000000至30000000之间的联系电话的银行账户文档"
> db.accounts.find( {
contact:{ $all:[
{ $elemMatch: { $gt: "10000000" $1t:"20000000" }},
{ $elemMatch: { $gt: "20000000", $1t: "30000000" }}
] }
}]
运算操作符
$regex
匹配满足正则表达式的文档
兼容 PCRE v8.41正则表达式库
在和 $in操作符一起使用时,只能使用 /pattern/<options>
# 读取用户姓名以c或者j开头的银行账户文档"
> db.accounts.find( { name:{ $in:[ /^c/, /^j/ ]}})
#读取用户姓名包含LIE(不区分大小写)的银行账户文档"
db.accounts.find( { name: { $regex: /LIE/, $options: "i"} } )
文档游标
db.collection.find()
返回一个文档集合游标
在不迭代游标的情况下,只列出前20个文档
var myCursor = db.accounts.find();
myCursor
myCursor[1]
// 游历完游标中所有的文档之后,或者在10分钟之后,游标便会自动关闭
// 可以使用 noCursorrimeout()函数来保持游标一直有效
var mycursor = db.accounts.find().noCursormimeout()
// 在这之后,在不遍历游标的情况下,你需要主动关闭游标
myCursor.close()
游标函数
- cursor.hasNext()
- cursor.next()
- cursor.forEach()
- cursor.1imit()
- cursor.skip()
- cursor.count(): 默认情况下,<applyskipLimit>为 false, 即 cursor.count()不会考虑 cursor.skip( )和 cursor.1imit()的效果
- cursor.sort(): { field: ordering} , 1表示由小及大的正向排序,-1表示逆向排序
> var myCursor = db.accounts.find( { name = "george" });
> while( myCursor.hasNext() ){
printjson(myCursor.next());
}
> myCursor.forEach(printjson)
> db.accounts.find( { name = "george" }).limit(1)
> db.accounts.find( { name = "george" }).skip(1)
> db.accounts.find( { name = "george" }).limit(0) # 等同不使用limit 返回所有
> db.accounts.find( { name: "george" }).limit(1).count() # 统计所有
> db.accounts.find( { name: "george" }).limit(1).count(true) # 统计limit后的数量
> db.accounts.find().sort( { balance: -1, name: 1 })
> db.accounts.find().sort( { balance: -1 }).limit(1)
# cursor.skip(), cursor.1imit(), cursor.sort()结合在一起使用时注意事项
# cursor.skip()在 cursor.1imit()之前执行
> db.accounts.find().limit(5).skip(3)
# cursor.sort()在cursor.skip()和 cursor.1imit()之前执行
> db.accounts.find().skip(3).limit(5).sort( { balance:-1})
文档投影
db.collection.find (, ) 不使用投影时,db.collection.find()返回符合筛选条件的完整文档 而使用投影可以有选择性的返回文档中的部分字段
{ field: inclusion] 1表示返回字段,0表示不返回字段店
# 只返回银行账户文档中的用户姓名"
> db. accounts. find( {}, { name: 1 })
# 不返回银行账户文档中的用户姓名(也不返回文档主键)”
> db.accounts.find({}, { name: 0, _id:0}
# 除了文档主键之外,我们不可以在投影文档中混合使用包含和不包含这两种投影操作
# 要么在投影文档中列出所有应该包含的字段,要么列出所有不应该包含的字段
> db.accounts.find({},{ name: 1, balance: 0, id: 0 })
注意事项