前言
MongoDB是目前非常主流的非关系型数据库,松散的数据结构(json和bson)便于存储复杂的数据类型,强大的查询语法(具备关系型数据库单表查询的大部分功能),支持创建索引,查询性能优。对于MongoDB的数据存储和MySQL数据库存储,单条数据可以看作是一个Map<String,Obect>和一个实体对象的区别,MongoDB可以随意存放各种字段及数据类型,MySQL需要插入在表设计时候定义好的数据字段及类型,在适用的场景下,这是MongoDB等非关系型数据库的一大优势。
知识点
- 简单查询(条件查询、分页查询、排序、操作符使用)
- 分组聚合(单字段分组、多字段分组)
- 更新、删除
查询
演示数据
user_info
姓名(name) | 年龄(age) | 性别(sex) | 住址(address) | 体重(weight) |
---|---|---|---|---|
卡戴珊 | 29 | 女 | 洛杉矶 | 60 |
乔治 | 30 | 男 | 洛杉矶 | 80 |
布克 | 23 | 男 | 菲尼克斯 | 80 |
东契奇 | 23 | 男 | 达拉斯 | 80 |
注意:name是MySQL关键字,实际开发中不要使用关键字作为字段名
简单查询
1 查询详细信息
select name, age, sex,address from user_info where name = '布克' limit 1;
复制代码
db.user_info.find({"name":"布克"},{"name":1,"age":1,"sex":1, "address":1}}).limit(1);
复制代码
1.1 多字段匹配
select name, age, sex,address from user_info where name = '布克' and address = '菲尼克斯' limit 1;
复制代码
db.user_info.find({"name":"布克", "address":"菲尼克斯"},{"name":1,"age":1,"sex":1, "address":1}}).limit(1);
复制代码
Monogo查询使用find()方法,find方法包含两个参数均为json结构,第一个参数是查询条件,第二个是指定需要查询的键,值为0代表不查询此字段,1代表查询此字段,此条mongo查询涉及两个方法find(query, projection),limit(size),对应mysql中的select和limit,区别在于mysql中limit可以包含offset参数及limit参数,下面展示mongo中如何实现mysql分页中的limit双参数写法,find的第一个参数填写空的json({})代表的是查全表,第二个参数填空json({})代表的是获取所有字段
db.user_info.find({},{})或db.user_info.find() = select * from user_info
2 分页查询
select name, age, sex,address,weight from user_info limit 1,1;
复制代码
db.user_info.find({},{"name":1,"age":1,"sex":1, address":1,"weight":1}).limit(1).skip(1)
复制代码
MongoDB要实现从第多少条往后查询多少条需要将limit方法和skip方法组合使用,MySQL中的有limit更有弹性
3 排序查询
3.1 单字段排序
SELECT name,age,sex,address,weight FROM `user_info` ORDER BY age desc
复制代码
db.user_info.find({},{"name":1,"age":1,"sex":1, "address":1}).sort({"age":-1})
复制代码
mysql中使用order by 字段 进行排序(可以置顶升序asc、降序desc,不指定则默认降序),mongo中使用sort({“key”: -1或1})进行排序,-1为降序、1为升序
3.2 多字段排序
SELECT name,age,sex,address,weight FROM `user_info` ORDER BY age desc,weight asc
复制代码
db.user_info.find({},{"name":1,"age":1,"sex":1, "address":1,"weight":1}).sort({"age":-1,"weight":1})
复制代码
4 模糊查询
SELECT name,age,sex,address,weight FROM `user_info` where address like '%洛%';
复制代码
db.getCollection('user_info').find({"address":{'$regex':'洛'},{"name":1,"age":1,"sex":1,"address":1,"weight":1})
复制代码
$regex相当于是一个简化的正则判断,Mongo查询规则主要为以xx开头或结尾,包含xx,是否区分大小写
5 常用条件操作符
条件操作符 | 描述 | 示例 |
---|---|---|
$ne | 不等于 | db.getCollection(‘user_info’).find({“age”:{‘$ne’:23}}) |
$lt | 小于 | 同上 |
$gt | 小于等于 | 同上 |
$gt | 大于 | 同上 |
$gte | 大于等于 | 同上 |
$or | 或 | db.getCollection(‘user_info’).find({“$or”:{‘name’:’布克’,’age’:29}} |
$nor | 或取反 | 同上 |
$in | in查询 | db.getCollection(‘user_info’).find({‘name’:{‘$in’:[‘布克’,’卡戴珊’]}}) |
5.1 组合使用示例
大于23岁小于等于30岁
db.getCollection('user_info').find({"age":{'$gt':23,'$lte':30}};
年龄在23到30,住在洛杉矶、达拉斯的人
db.getCollection('user_info').find({"age":{'$gt':23,'$lte':30}, 'address':{'$in':['洛杉矶','达拉斯']}};
复制代码
简单查询总结
简单查询部分介绍了我们常用的条件查询,分页查询,条件操作符的应用,熟练掌握上面的命令就能够在开发中对数据进行常规的查询操作,下面介绍一下Mongo聚合分组查询的应用。
分组聚合
难点
mongo分组聚合的语法单独拿出来并不难,但是在结合了复杂条件,起别名后就会层级比较多,建议先熟练简单的分组,使用json编辑器进行编辑,能够清楚看清层级关系,便于自己理解
单字段分组
按address分组统计大于18岁的总体重(单字段分组)
SELECT address, SUM(weight) weightSum FROM `user_info` where age >=18 GROUP BY address
复制代码
db.user_info.aggregate([{"$match":{"age":{"$gte":18}}},{"$group":{"_id":"$address","weightSum":{"$sum":"$weight"}}}])
复制代码
mongo分组聚合使用aggregate方法,mongo的每一条数据会有一个唯一的_id,会在插入时候自动生成,也可以在插入的时候手动设置
- aggregate方法参数为数组[{},{}]
- 数组第一个元素格式固定为{“$match”:{}},key就是匹配操作符,值对应的就是简单查询中的条件比如 {“$match”:{“address”:”洛杉矶”}}就是sql group前的where address = “洛杉矶”
- 第二个参数格式为{“$group”:{}},$group是mongo中的分组操作符,值中如果按照address分组,就是_id:”$address”,然后就是分组后要做的聚合操作,可以相当于别名,值也是一个json,值得json key就是函数,value就是$+统计的字段
多字段分组
按address和性别分组统计平均体重(多字段分组)
db.user_info.aggregate([{"$match":{"age":{"$gte":18}}},{"$group":{"_id":["$address","$sex"],"weightSum":{"$avg":"$weight"}}}])
复制代码
区别就是分组中_id对应的值变成多个字段分组字段的数组,返回值中_id也相应的变成数组
删除
delete from user_info where name = '布克' limit 1;
复制代码
db.collection.remove(
{'name':'布克'},
ture
)
复制代码
mongo删除使用remove方法,方法第一个参数为删除条件,与find的查询条件语法相同,第二个参数为是否删除一个,true就只会删除条件匹配到的第一个数据
新增
insert into user_info(name, age, address, sex) values("保罗","36","菲尼克斯","男")
复制代码
db.user_info.insert({"name":"保罗","age":"36","address":"菲尼克斯","sex":"男"})
复制代码
mongo插入语句也是insert,插入一条数据为一个json结构,key就是字段名称, value就是值,mongo集合中每条数据相同的字段名可以是不同的类型,这也是灵活的体现,但是不推荐这样使用,不便于维护
更新
mongo更新方法很强大,update方法包含四个参数,第一个为条件(格式为{}),第二个为更新的值(格式为{‘$set’:{‘字段’:’值’}),第三个为upsert(存在符合条件的即更新,不存在即插入,默认false),第四个为是否更新多个(默认fasle只更新符合条件的第一个)
更新卡戴珊的住址
update user_info set address="纽约" where name = "卡戴珊" limit 1;
复制代码
ps:mysql中更新插入的方法有很多,比如replace into会根据数据中的主键或者唯一索引检查数据是否存在,存在情况会导致自增id发生改变,需要慎用
db.user_info.update({"name":"卡戴珊"},{"$set":{"address":"纽约","telephone":10086}},true, false)
复制代码
可以看到我在更新卡戴珊的时候,还添加了一个之前不存在的字段telephone,这样卡戴珊的个人信息就会多出一个telephone,这也是MongoDB松散的体现
最后
本文涉及了开发中常用的简单查询及分组聚合,覆盖了绝大多数场景,通过与sql的对比快速学习mongo操作,希望能够帮助到有需要的人
点击学习MongoDB分表
分分钟学会MongoDB GridFs搭建文件服务
了解一下Redis缓存及本地缓存设计实践