简介
MongoDB 是一个基于分布式文件存储的数据库,由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。是非关系型数据库中功能最丰富,最像关系数据库的。支持数据结构类似 json 的 bson 格式。可以存储比较复杂的数据类型。MongoDB 的查询语言非常强大,类似面向对象的查询语言,几乎可以实现类似数据库单表查询的绝大部分功能,支持对数据建立索引。
高性能(相比关系型数据库),易部署,易使用。

对事务要求不高的业务都能被 MongoDB 取代。分片实现高可用,内部采用轮询的方式进行数据存储。
下载安装
下载安装
数据库结构
数据库存储使用的是集合,集合中存储的是文档,即树状结构数据。

MongoDB 默认端口 27017
在线文档教程
语法
1 2 3 4 5 6 7 8 9
| show dbs: 查询所有数据库 use 数据库名: 创建并且选中数据库,数据库已经存在则直接选中 db: 查询当前选择的数据库 db.dropDatabase(): 删除当前选中的数据库 show collections: 查询当前库中的集合 db.createCollection("集合名"): 创建集合 db.集合名.drop(): 删除集合
注意: db.集合名 == db.getCollection("集合名")
|
数据类型
支持的数据类型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| String(字符串): mongodb中的字符串是UTF-8有效的 Integer(整数): 存储数值。整数可以是32位或64位,具体取决于您的服务器 Boolean(布尔): 存储布尔(true/false)值 Double(双精度): 存储浮点值 Arrays(数组): 将数组或列表或多个值存储到⼀个键中 Timestamp(时间戳): 存储时间戳 Object(对象): 嵌⼊式⽂档 Null (空值): 存储Null值 Symbol(符号): 与字符串相同,⽤于具有特定符号类型的语⾔ Date(⽇期): 以UNIX时间格式存储当前⽇期或时间 Object ID(对象ID) : 存储⽂档ID Binary data(⼆进制数据): 存储⼆进制数据 Code(代码): 将JavaScript代码存储到⽂档中 Regular expression(正则表达式): 存储正则表达式
|
新增操作
往集合中新增文档,当集合不存在时,会自动先创建集合,再往集合中添加文档。
1 2
| db.集合名.insert(文档) db.集合名.find() 查询集合中所有文档
|
操作成功时,会给文档生成一个_id 字段,就是文档的主键。
1 2 3
| // 插入一个员工对象 db.users.insert({id: NumberLong(1), name: "小妖", age: NumberInt(18)}) db.users.insert({id: 2, name: "bunny", age: 20})
|
注意,直接写数字默认是 Double 类型。
更新操作
语法
1 2 3 4 5 6 7 8 9 10 11 12 13
| db.集合名.update( <query>, <update>, { upsert: <boolean>, multi: <boolean>, writeConcern: <document> } )
简化方法: 更新1个:db.集合名.updateOne( ... ) 更新所有:db.集合名.updateMany( ... )
|
参数:
- query: update 查询条件,类似 sql update查询 where 后面的条件
- update: update 的对象和一些更新的操作符(如$, $inc) 等,也可以理解为 sql update 查询,set 后面的
- upsert: 可选,这个参数的意思是,如果不存在update 的记录,是否插入 objNew,true 为插入,默认是 false,不插入。
- multi: 可选,mongodb 默认是 false,只更新找到的第一条记录,如果参数为 true,就把按调价查出来多条记录全部更新。
- writeConcern: 可选,抛出异常的级别
实例
1 2 3 4 5
| //把一个带有name=逍遥的文档,修改其age值为30 db.employees.updateOne({name: "逍遥"}, {$set: {age: 30}})
//修改所有name=逍遥的文档,修改其name=bunny,age=20 db.employees.updateMany({name: "逍遥"}, {$set: {name: "bunny", age: 30}})
|
删除操作
语法
1 2 3 4 5 6 7 8 9 10 11
| db.集合名.remove( <query>, { justOne: <boolean>, writeConcern: <document> } )
简化方法: 删除1个:db.集合名.deleteOne( ... ) 删除所有:db.集合名.deleteMany( ... )
|
- query :(可选)删除的文档的条件。
- justOne : (可选)如果设为 true 或 1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除 所有匹配条件的文档。
- writeConcern :(可选)抛出异常的级别
实例
1 2 3 4 5 6 7 8
| // 删除 _id=xxx 的文档 db.users.deleteOne({_id: objectId("xxx")})
// 删除所有带有 name=bunny 的文档 db.users.deleteMany({name: "bunny"})
// 删除当前数据库中所有文档 db.users.deleteMany()
|
查询操作
语法
db.集合名.find(query, projection)
- query: 可选,使用查询操作符指定查询条件
- projection: 可选,使用投影操作符指定返回的键。查询时返回文档中所有键值,只需省略该参数即可(默认省略)
实例
1 2 3 4 5 6 7 8 9 10 11
| // 查询所有文档 db.users.find() // 排序查询 db.users.find().sort({字段: 1}) -> 按照字段升序排列 db.users.find().sort({字段: -1}) -> 按照字段降序排列 // 分页查询 sikp(num): 跳过 num 个文档,相当于 start limit(num): 限制显示 num 个文档,相当于 pageSize
db.users.find().skip(num).limit(num) 需求:按年龄降序排列,查询第二页,每页显示3个
|
高级查询
等值查询
find({字段: 值})
比较查询
find({字段: {比较操作符: 值, ...}})
- 大于(>) ->
$gt
- 小于(<) ->
$lt
- 大于等于(>=) ->
$gte
- 小于等于(<=) ->
$lte
- 不等于(!=) ->
$ne
- 集合运算 ->
$in
, {name: {$in:["xiaoyao", "bunny"]}}
- 判断存在 ->
$exists
, {name: {$exists: true}}
逻辑查询:
&& -> $and
|| -> $or
! -> $not
模糊查询
MongoDB 的模糊查询使用的是正则表达式语法 {name: {$regex:/^.*keyword.*$/}}
,实际上 MongoDB 也是不擅长执行模糊查询的,在实际开发中不使用。
设置用户
用户设置
在 MongoDB 的配置文件:安装目录/Server/bin/mongod.cfg 中,如果修改了以下配置
1 2 3
| # 在29行位置,配置开启权限认证 security: authorization: enabled
|
如果完成了上述配置,重启服务器后,登录时需要输入密码,否则不能执行任何命令。
Spring Data MongoDB
准备工作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| <packaging>jar</packaging>
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> </parent>
<dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.6</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency> </dependencies>
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
|
配置连接参数
application.properties
1 2 3 4 5 6 7
|
spring.data.mongodb.uri=mongodb://root:admin@localhost/mongotest?authSource=admin
logging.level.org.springframework.data.mongodb.core=debug
|
操作数据库方案
使用,在 MongoDB 中提供了2个方案操作数据库。
高度封装的方案: MongoRepository
可以自定义配置方案:MongoTemplate
MongoRepository
该接口对 MongoDB 数据的常用操作进行了封装,只需要写个接口继承该接口就能直接拥有 CRUD 的基本操作,学习 JPA 的方法命名规范,可以完成各种复杂的高级操作,底层会调用 MongoTemplate 方法。
1 2 3 4 5 6 7 8 9 10 11
|
@Repository public interface UserMongoRepository extends MongoRepository<User, ObjectId> { List<User> findByName(String name); }
|
创建接口,放在 respository 包下。使用 Spring-data 的技术,都推荐放在 respository 包下。
需要配置 domain 类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @NoArgsConstructor @Setter @Getter @ToString @Document("users") public class User extends BaseDomain { @Id private ObjectId _id;
private String name; private Integer age; @DateTimeFormat private Date bornDate; private String headImg; }
|
增删改
1 2 3 4 5 6 7 8 9 10 11 12
| @Test public void testSaveOrUpdate() { System.out.println(repository); User user = new User(); user.setName("lz"); user.setAge(19); System.out.println(user); repository.save(user); System.out.println(user); }
|
如果配置了 id,调用 save 方法就是修改操作。
日志如下
1 2 3 4 5 6
| 2019-10-08 16:46:22.062 DEBUG 2584 --- [ main] o.s.data.mongodb.core.MongoTemplate : Inserting Document containing fields: [name, age, _class] in collection: users 2019-10-08 16:46:22.107 INFO 2584 --- [ main] org.mongodb.driver.connection : Opened connection [connectionId{localValue:2, serverValue:10}] to 127.0.0.1:27017
2019-10-08 16:54:58.307 DEBUG 2636 --- [ main] o.s.data.mongodb.core.MongoTemplate : Saving Document containing fields: [_id, name, age, _class] 2019-10-08 16:54:58.342 INFO 2636 --- [ main] org.mongodb.driver.connection : Opened connection [connectionId{localValue:2, serverValue:12}] to 127.0.0.1:27017
|
inserting 新增,saving 更新,removing 删除
查询:查多个
1 2 3 4 5
| @Test public void testQuery() { List<User> list = repository.findAll(); list.forEach(System.out::println); }
|
1 2 3 4 5 6 7 8
|
Page<User> page = repository.findAll(PageRequest.of(0, 3)); page.getContent().forEach(System.out::println);
|
1 2 3 4 5
| @Test public void testget() { Optional<User> byId = repository.findById(new ObjectId("5d9c4cde8670510a18497809")); byId.ifPresent(System.out::println); }
|
JPA 方法命名规范
只要符合 JPA 方法命名规范,不需要写方法实现。
关键字 |
例子 |
JPQL |
And |
findByNameAndAge(String name, Integer age) |
where name = ? and age = ? |
Or |
findByNameOrAge(String name, Integer age) |
where name = ? or age = ? |
Is |
findByName(String name) |
where name = ? |
Between |
findByAgeBetween(Integer min, Integer max) |
where age between ? and ? |
LessThan |
findByAgeLessThan(Integer age) |
where age < ? |
LessThanEqual |
findByIdLessThanEqual |
where id <= ? |
GreaterThan |
findByIdGreaterThan |
where id > ? |
GreaterThanEqual |
findByIdGreaterThanEqual |
where id > = ? |
After |
findByIdAfter |
where id > ? |
Before |
findByIdBefore |
where id < ? |
IsNull |
findByNameIsNull |
where name is null |
isNotNull,NotNull |
findByNameNotNull |
where name is not null |
Like |
findByNameLike |
where name like ? |
NotLike |
findByNameNotLike |
where name not like ? |
StartingWith |
findByNameStartingWith |
where name like ‘?%’ |
EndingWith |
findByNameEndingWith |
where name like ‘%?’ |
Containing |
findByNameContaining |
where name like ‘%?%’ |
OrderBy |
findByIdOrderByXDesc |
where id=? order by x desc |
Not |
findByNameNot |
where name <> ? |
In |
findByIdIn(Collection<?> c) |
where id in (?) |
NotIn |
findByIdNotIn(Collection<?> c) |
where id not in (?) |
True |
findByAaaTue |
where aaa = true |
False |
findByAaaFalse |
where aaa = false |
IgnoreCase |
findByNameIgnoreCase |
where UPPER(name)=UPPER(?) |
MongoTemplate
SpringBoot 完成了自动配置,直接注入即可。依靠该对象可以完成任何 MongoDB 操作,一般和 MongoRepository 分工合作,多数用于复杂的高级查询以及底层操作。
1 2
| @Autowired private MongoTemplate template;
|
1 2
| List<T> mongoTemplate.find(Query query, Class<T> type, String collectionName);
|
条件封装 Query
1 2 3 4 5 6 7
| Criteria.where(String key).is(Object val); Criteria.orOperator(Criteria...);
Criteria.where(String key).regex(String regex);
|
最后通过 addCriteria 把条件封装到 Query 对象中
1 2
| Query对象.addCriteria(Criteria criteria); Query对象.skip(start).limit(pageSize);
|
实例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| @Autowired private MongoTemplate mongoTemplate;
public void testQuery1() throws Exception {
Query query = new Query(); query.skip(3).limit(3); query.with(new Sort(Sort.Direction.ASC, "id"));
List<User> list = mongoTemplate.find(query, User.class, "users"); list.forEach(System.err::println);
}
@Test public void testQuery2() throws Exception {
Criteria criteria = Criteria.where("name").is("bunny"); Query query = new Query(); query.addCriteria(criteria);
List<User> list = mongoTemplate.find(query, User.class, "users"); list.forEach(System.err::println);
}
@Test public void testQuery3() throws Exception {
Criteria criteria = new Criteria().orOperator(
Criteria.where("name").is("bunny"),
Criteria.where("age").lt(30));
Query query = new Query(); query.addCriteria(criteria);
List<User> list = mongoTemplate.find(query, User.class, "users"); list.forEach(System.err::println);
}
@Test public void testQuery4() throws Exception { Criteria criteria = new Criteria().andOperator(Criteria.where("name").regex(".*wang.*"), Criteria.where("age").gte(30).lte(32)); Query query = new Query(); query.addCriteria(criteria);
List<User> list = mongoTemplate.find(query, User.class, "users"); list.forEach(System.err::println); }
|