MongoDB入门
一、入门基础
1. 入门简介
三个概念:
- 数据库 — database
- 数据库是一个仓库,在仓库中可存放的集合
- 集合 — collection
- 集合类似于数组,在集合中可以存放文档
- 文档 — document
- 文档是数据库中最小的单位,我们存储和操作的内容都是文档
- 在MongoDB中,在操作document时,如果数据库和集合不存在时,会自动创建。
入门指令:
- show dbs 或者 show databases // 查看所有数据库基本信息【数据库名 数据库大小】
- show <…>s //查看某某东西
- use dbName //进入指定的数据库[dbName]中
- 数据库【文档】的增删查改[CRUD]
2. 基础指令
2.1 基本的CRUD操作
(1) 插入文档:
参考官网:https://docs.mongodb.com/v4.2/tutorial/insert-documents/
- db.<collection>.insert(doc) //向集合[collection]中插入数据[内容:doc]
- 向集合[collection]中插入一个或多个文档
- 当我们向集合中添加数据时,如果没有指定'_id'属性值,则数据库会自动添加'_id'
数据库默认调用'ObjectId()'生成'_id',且保证唯一性。
ObjectId()
- 开始插入数据
# 插入单条数据:
db.stus.insert({name:"猪八戒",age:41,gender:"男"})
db.stus.insertOne({name:"猪八戒4",age:39,gender:"男"}); # 3.2后添加的
# 插入多条数据【插入一个集合数据】
db.stus.insert([
{name:"猪八戒",age:41,gender:"男"},
{name:"猪八戒的媳妇",age:21,gender:"女"},
]);
db.stus.insertMany([
{name:"猪八戒6",age:39,gender:"男"}
]);
- 手动给数据库添加'_id'属性:【确定自己的'_id'有唯一性】
db.stus.insert({_id:"hello",name:"猪八戒",age:41,gender:"男"}); # 3.2后添加的
(2) 查询文档:
参考官网:https://docs.mongodb.com/v4.2/tutorial/query-documents/
- db.collection.find(..) 查询指定集合符合条件的所有数据文档
# 返回一个数组,即可以指定查找的位置
- find('{<field1>: <value1>, ...}'): 用来查询集合中所有的符合条件参数
- find('{<field1>: {<operator1>:<value1>}, ...}') # operator 是指定的操作符
参考官网:'https://docs.mongodb.com/v4.2/reference/operator/query/#query-selectors'
# 测试1:db.collection.find({<field1>: <value1>, ...});
# 查询所有数据信息
db.stus.find();
db.stus.find()[1] ; # 指定能查找到的所有元素的,第二个数据
- find() --- 返回一个文档的'集合'/'数组'
# 查询指定条件的数据信息【_id=hello and name=猪八戒】
db.stus.find({
_id:"hello",
name:"猪八戒"
})
- 查询一个数据对象 返回一个文档【数据的最小存储单位】
db.stus.findOne({...}); #查询一条数据,如果存在多条指定条件的数据,则报错
- 查询 指定条件的个数【只有返回一个数组,才存在的函数】
db.collection.find( {...} ).count() ; # 返回查询数据的个数
- '.count()' or 'length()' 返回查询数据的个数
总结:
- 1. find() 与 findOne() 的特点:
- find() 返回一个数据文档数组【数组存在的函数:count() 和 length() 函数】
- findOne() 返回一个数据文档,相当于一个对象数据
- 2. find( {<field1>: <value1>, ...} ) 查找的特点:
- (1) 字符串 和 整形数值 有很大区别【尤其在自定义 '_id' 属性时】
查询运算符,参考官网:https://docs.mongodb.com/v4.2/reference/operator/query/#query-selectors
(3) 修改文档:
- db.collection.update()
- update( {查询条件} , {更新的数据} )【默认情况下,'新文档数据' 完全代替 '旧文档数据'】
'注意:'
1. '当查询条件有多个时,默认只修改第一条文档数据'
- 修改操作符:
- $set --- 用来修改【或添加】指定文档属性
- $unset --- 用来删除文档的指定属性
- update({查询条件},{更新的数据},{多个参数【可选】})
- 参数有: upsert:<boolean>, #
multi:<boolean>, # 是否修改多个【默认为 false】
writeConcern:<document>, #
collation:<document> #
- db.collection.updateOne({..},{..}); --- 修改符合条件的 一个文档数据
db.collection.updateMany({..},{..}); --- 修改符合条件的 多个文档数据
- 'updateOne(...)' --- 当查询条件有多个时,默认只修改'第一条'文档数据
- 'updateMany(...)' --- 当查询条件有多个时,会同时修改'多条'文档数据
# 测试1:db.collection.update( {..} , {..} )
# 案例:修改name=“张三” 的文档,并将对象修改为:age=42,position="总经理"
db.stus.update(
{name="张三"},
{age:42,position:"总经理"}
)
- '结果':name="张三"的文档数据,被替换成了{age:42,position:"总经理"}的文档数据【name属性丢失】
- '结论':先查找到与查询匹配的结果,然后将就对象'A'替换成新的对象数据'B'【原先的数据被抛弃】
# 测试2: db.collection.update({..},{$set:{..}})
# 案例:修改name=“张三” 的文档,并将对象修改为:age=42,position="总经理"
db.stus.update(
{name="张三"},
{$set:
{age:42,position:"总经理"}
}
)
- '结果':name="张三"的文档数据,只有属性'age'和'position'的数据被修改,其他的保持不变
- '结论':先查找到与查询匹配的结果,然后匹配相关属性。若存在指定的属性,则修改;若不存在指定属性,则新建一个属性
# 测试3: db.collection.update({..},{$unset:{..}})
# 案例:修改name=“张三” 的文档,并删除对象属性:position【可以传递任意数据,但必须存在值】
db.stus.update(
{name:"张三"},
{$unset:{
position:"1"
}}
)
# 测试4:db.collection.updateOne({..},{..});
db.stus.updateOne(
{name:"张三"},
{$set:
{position:"副经理"}
}
);
- '结果':查询条件有'两条文档',但只修改'第一条'文档数据
- '结论':当查询条件有多个时,默认只修改'第一条'文档数据
# 测试5:db.collection.updateMany({..},{..});
db.stus.updateMany(
{name:"张三"},
{$set:
{position:"总经理"}
}
);
- '结果':查询条件有'两条文档','同时修改两条'文档数据
- '结论':当查询条件有多个时,会同时修改'多条'文档数据
更新的运算符:参考网址:https://docs.mongodb.com/manual/reference/operator/update/
(4) 删除文档:
- db.collection.deleteMany() # 删除多条文档数据
db.collection.deleteMany({<field1>:<value1>,...})
- 删除'所有符合'条件的文档
- db.collection.deleteOne() # 删除一条文档数据
db.collection.deleteOne({<field1>:<value1>,...})
- 删除'第一条符合'条件的文档
- db.collection.remvoe()
db.collection.remove({<query>,<justOne>);
- justOne<boolean> # 是否只删除一个文档
- 1. 默认删除'所有符合'条件的文档
-
# 测试1:db.collection.deleteMany( {<field1>:<value1>,...} )
# 案例:删除 status="A" 的文档数据
db.inventory.deleteMany({ status : "A" })
- '结果':status='A'的所有文档数据被删除
- '注意':db.inventory.deleteMany({}) 这是删除集合中所有的文档数据
- 但这种效率很低,这是一条一条删除文档数据的,可以直接使用指令:'db.inventory.drop()' 删除指定集合。
# 测试2:db.collection.deleteOne( {<field1>:<value1>,...} )
# 案例:删除为 status="D" 的文档数据
db.inventory.deleteOne({ status : "D" })
- '结果':status='D',中的第一条数据
# 测试3:db.collection.deleteMany( {<field1>:{ <operator1>:<value1>},...} )
# 案例:删除age>50的数据
db.inventory.deleteMany({
age:
{$gt: 50}
}
)
- '结果':删除所有'age>50'的文档数据
操作符参考网页:https://docs.mongodb.com/v4.2/reference/operator/query/#query-selectors
2.2 基本的CRUD — 练习题
3. 文档之间的关系
3.1 文档之间的对应关系
- 一对一
- 一对多
- 多对多
1. 一对一
- 例如:一夫一妻制
db.test.insert([
{name:"小花",husband:{name:"张三"}},
{name:"小红",husband:{name:"李四"}},
]);
- '解释': 小花的丈夫是张三。一个妻子对应一个丈夫【丈夫张三被妻子'内嵌'在内部】
2. 一对多
- 例如:用户订单服务【一个用户,可以下多个订单】
# 准备数据
db.users.insert([
{name:"张三",money:2000},
{name:"李四",money:3000}
]);
db.order.insert([
{list:["香蕉","大栗子","苹果"],user_id:ObjectId("5f2ffceff8723acd57eb61f2")},
{list:["漫画","大猪蹄子"],user_id:ObjectId("5f2ffceff8723acd57eb61f3")},
{list:["桃子"],user_id:ObjectId("5f2ffceff8723acd57eb61f3")}
]);
# 测试1:查找name='张三'的所有订单
var userId = db.users.findOne({name:"张三"})._id
db.order.find({user_id: userId});
- 查询结果:{ "_id" : ObjectId("..1"), "list" : [ "香蕉", "大栗子", "苹果" ], "user_id" : ObjectId("..u") }
# 测试2:查找name='李四'的所有订单
var userId = db.users.findOne({name:"李四"})._id
db.order.find({user_id: userId});
- 查询结果:
{ "_id" : ObjectId("..1"), "list" : [ "漫画", "大猪蹄子" ], "user_id" : ObjectId("..u") }
{ "_id" : ObjectId("..2"), "list" : [ "桃子" ], "user_id" : ObjectId("..u") }
3. 多对多
4. 查询排序和投影
-> 测试数据:
use empInfo
db.emp.insert([
{name:"张三",age:43},
{name:"李四",age:23},
{name:"王五",age:32},
{name:"李辉",age:22}
]);
(1)排序【sort()】:
- db.<collection>.find(..).sort()
- sort({<field1>:<value1>,...})
- 'value':一般传'1'【升序】或'-1'【降序】
# 案例:查询 emp 信息,并按年龄[age]升序进行显示
> db.emp.find().sort({age:1});
(2)投影:
- db.<collection>.find({query},{<field1>:1/0,...})
- 默认'_id'=1
# 案例:查询所有 emp 信息,并显示姓名
> db.emp.find({},{_id: 0 , name: 1});
- '结果':只显示'name'属性值