目录
一、介绍
二、安装指导
2.1 下载
2.2 安装注意事项
2.3 配置环境变量
2.4 校验是否配置成功
2.5 启动服务器
2.6 打开客户端
2.7 退出
2.8 修改参数配置
2.9 设置开启自启动服务
三、MongoDB基本操作
3.1 基本概念
3.2 基本命令
3.3 数据库的crud命令
四、图形化界面软件
4.1 mongodbmanagerfree_inst.exe
五、命令演示(crud)
5.1 插入文档
5.2 查询文档
5.3 修改文档
5.3.1 追加文档
5.3.2 删除某个字段
5.3.3 替换文档(谨慎使用)
5.4 删除文档
六、设置账号密码
七、与SpringBoot整合
7.1 pom.xml
7.2 application.yml
7.3 常用方法
7.4 代码演示(附常见方法使用说明)
7.5 部分效果展示
一、介绍
MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。
MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。
现在4.x以后引入了跨节点事务特性,可以粗浅的说关系型数据库能做的,它基本都能做了。
至于MongoDB是否在未来能够替代MySQL,这个还有得讨论。不过作为程序员而言,数据库只是工具,用什么工具并不重要,我们要习惯拥抱变化才能走的更长远。
二、安装指导
2.1 下载
下载地址:Download MongoDB Community Server | MongoDB
此文档使用的版本为:3.2.22
2.2 安装注意事项
建议自定义安装,修改一下安装路径,其他的就下一步下一步即可。
2.3 配置环境变量
2.4 校验是否配置成功
任意路径打开cmd窗口,输入mongod,如果没有出现找不到指令则说明配置成功。
以上提示报初始化异常,说没有找到data目录。
那么我们可以手动添加mongoDB的数据库目录,到它指定的路径下。即c:\data\db\
2.5 启动服务器
以上数据库目录创建完成后,我们就可以再次使用mongod命令启动mongodb了。
出现以上界面则说明启动成功。
2.6 打开客户端
注意启动服务器界面不要关闭,再次启动一个cmd窗口,输入mongo,则会去连接mongoDB ,出现 > ,则说明已经成功进入了客户端界面了。
2.7 退出
直接使用ctrl + c 即可退出。
2.8 修改参数配置
修改MongoDB数据库目录
默认情况下,是在C:\data\db\下的,我们也可以为它指定目录。方法是在启动数据库时追加命令。
mongod --dbpath 指定目录地址
修改默认端口
默认启动时,端口号为27017,如果想要修改也只需要追加参数即可。
mongod --port 指定端口号
注意:参数是可以同时追加多个的,并非指定数据库目录同时不能指定端口号。
2.9 设置开启自启动服务
在当前数据库db同级目录下,创建一个log文件夹
在mongodb的安装home目录下新建配置文件mongod.cfg
内容如下(如果想更改位置也可以自己指定):
systemLog:
destination: file
path: c:\data\log\mongod.log
storage:
dbPath: c:\data\db
已管理员权限运行cmd,然后执行如下命令
sc.exe create MongoDB binPath= "\"D:\it\MongoDB3.2.22\bin\mongod.exe\" --service --config=\"D:\it\MongoDB3.2.22\mongod.cfg\"" DisplayName= "MongoDB" start= "auto"
启动mongodb服务
测试
此时,你只需要输入mongo命令,无需再启动MongoDB的服务器了。
如果启动失败,证明上面的操作有误
在控制台输入 sc delete MongoDB 删除之前配置的服务,然后再从第一步重新开始。
三、MongoDB基本操作
3.1 基本概念
MongoDB的结构分为:
database(数据库)、collection(集合)、document(文档)
与关系型数据库比较,其实就相当于数据库、表、记录。
3.2 基本命令
# 查看所有数据库,默认只有一个叫local的数据库
show databases;
# 进入某个数据库,如果数据库不存在,也不影响进入,只要为数据库创建了内容,会自动生成该数据库
use 数据库名;
# 查看当前在哪个数据库中
db
# 查看当前数据库中所有的集合
show collections;
3.3 数据库的crud命令
这里只是简单演示一下,后面使用图形化界面工具重点演示
向数据库中插入文档
db.集合名.insert(文档)
例如:
向my-test数据库中 ,stus集合中插入一个新的学生对象:{name:"王二",age:12,gender:"男"}
db.stus.insert({name:"王二",age:12,gender:"男"});
查询集合中的所有文档
db.集合名.find();
四、图形化界面软件
4.1 mongodbmanagerfree_inst.exe
安装默认下一步即可。登录也是
4.2 navicat
其实个人认为最好用的还是navicat
五、命令演示(crud)
5.1 插入文档
当我们向集合插入文档时,如果没有给文档指定 _id 属性,则数据库会自动为文档添加 _id。该属性作为文档的唯一标识。
我们也可以自己生成,但是如果自己生成一定要保证其唯一性。建议使用默认的自动生成。
总结
-
insert()
-
insertOne()
-
insertMany()
后面两个方法其实本质上也属于第一个。insertOne则只能插入一个文档,而insertMany()则必须使用数组的形式插入,可以是多个,也可以是一个。
5.2 查询文档
find()
-
不传参数表示查询查询集合中所有文档
-
传递文档参数则表示查询当前集合中指定文档参数的全部文档
-
返回的是数组
-
后面追加count()表示统计数量
findOne()
-
查询符合条件的第一个文档
-
返回的是文档对象
举例:
5.3 修改文档
5.3.1 追加文档
5.3.2 删除某个字段
第一个对象依然是条件,第二个对象使用$unset,然后对象里面的属性就是要删除的属性,属性的值是多少不重要。
5.3.3 替换文档(谨慎使用)
该方法只要符合条件的都会替换
db.west.update( {"_id" : ObjectId("6490023fd5582aef179c3bc9"}, {age:8})
5.4 删除文档
remove()
-
默认删除多个
-
如果第二个参数设置为true,则只会删除第一个
-
必须传参,否则报错
-
如果传递{},则集合中所有的文档都删除了。如果想要删除所有的,建议使用db.集合名.drop() 效率更高。
deleteOne() 默认删除第一个
deleteMany()
一般情况下,数据库中的数据很少删除,所以一般不会调用删除命令。因为一旦删除就会永久丢失了。
一般我们也会像Mysql那样,设置逻辑删除字段。只是要求在查询的时候带上逻辑删除字段的条件。
六、设置账号密码
默认情况下,mongodb是没有账号密码的,需要我们手动进行设置,否则如果是线上环境,那绝对是裸奔了。
# 设置管理员用户名密码需要切换到admin库(系统默认要求的)
use admin
# 创建管理员
db.createUser({user:"hssy",pwd:"qwe!2345",roles:["root"]})
# 查看所有用户信息
show users
# 删除用户
db.dropUser("hssy")
登录
mongo -u 用户名 -p 密码 --authenticationDatabase=admin
但是我们发现,好像直接用mongo命令也能启动哦
这是因为我们启动MongoDB服务器的时候,没有以auth启动。当我们启动时使用--auth命令后,再使用mongo命令就无法看到数据库及其内容了。
我们也可以在某一个库下,创建管理员,这样该管理员只能针对该数据库有权限,其他数据库是无法操作的。
七、与SpringBoot整合
7.1 pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
7.2 application.yml
spring:
data:
mongodb:
uri: mongodb://hssy:qwe!2345@localhost:27017/my-test?authSource=admin
# uri 等同于下面的配置
# database: my-test
# host: localhost
# port: 27017
# username: hssy
# password: qwe!2345
# authentication-database: amin
7.3 常用方法
如下方法都是通过MongoTemplate对象调用。
方法名 | 返回值类型 | 解释 |
---|---|---|
getCollectionNames | Set<String> | 获取当前库下全部集合名称 |
collectionExists(String collectionName) | boolean | 判断当前集合名称是否存在 |
createCollection(String collectionName) | MongoCollection<Document> | 新建集合 |
dropCollection(String collectionName) | 无 | 删除集合 |
findAll(Class<T> entityClass, String collectionName) | <T> List<T> | 查询指定集合中的全部文档,第一个参数是告诉MongoDB用哪个实体类映射 |
find(Query query, Class<T> entityClass, String collectionName) | <T> List<T> | 根据条件查询指定集合中的文档,第一个参数是查询条件 |
findById(Object id, Class<T> entityClass, String collectionName) | <T> T | 根据id查询指定集合中的文档,因为id是唯一的,所以只会有一个返回值 |
insert(T objectToSave, String collectionName) | <T> T | 向指定集合新增一条文档。需要指定集合名。 |
insert(T objectToSave) | <T> T | 向指定集合新增一条文档,没有指定集合名,默认根据实体类名生成。另外,无论是否指定集合名,即使不存在该集合,新增的时候也会自动创建该集合。 |
upsert(Query query, UpdateDefinition update, Class<?> entityClass) | UpdateResult | 按条件更新文档,如果查询条件未找到记录,则会新增一条记录。如果查询出符合条件的数据有n条,则会修改这n条数据 |
remove(Query query, Class<?> entityClass, String collectionName) | DeleteResult | 按条件删除文档 |
count(Query query, @Nullable Class<?> entityClass, String collectionName) | long | 查询指定条件下某集合的文档总条数 |
7.4 代码演示(附常见方法使用说明)
package com.hssy.smartaide.controller.mongodb;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.hssy.smartaide.common.Result;
import com.hssy.smartaide.common.constant.enums.StatusCode;
import com.hssy.smartaide.entity.User;
import com.hssy.smartaide.entity.mongo.ConsumerDetail;
import com.hssy.smartaide.form.mongo.ConsumerDetailQueryForm;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDate;
import java.util.List;
import java.util.Set;
@Api(tags = "MongoDB数据库操作")
@RestController
@RequestMapping("mongo")
public class MongoController {
@Autowired
private MongoTemplate mongoTemplate;
@ApiOperation("查询所有集合名称")
@GetMapping("findAllCollectionName")
public Result<Set<String>> findAllCollectionName(){
Set<String> collectionNameSet = mongoTemplate.getCollectionNames();
return Result.success(collectionNameSet);
}
@ApiOperation("判断指定集合是否存在")
@GetMapping("isExistCollection")
public Result<Boolean> isExistCollection(@RequestParam(value = "collectionName") String collectionName){
return Result.success(mongoTemplate.collectionExists(collectionName));
}
@ApiOperation("新建集合")
@PostMapping("createCollection")
public Result<String> createCollection(@RequestParam(value = "collectionName") String collectionName){
boolean isExistCollection = mongoTemplate.collectionExists(collectionName);
if (!isExistCollection){
mongoTemplate.createCollection(collectionName);
return Result.success(StatusCode.CREATE_SUCCESS.getCode(),StatusCode.CREATE_SUCCESS.getValue());
}else {
return Result.error(-1,"当前数据库已存在该集合,添加失败!");
}
}
@ApiOperation("删除集合")
@PostMapping("dropCollection")
public Result<String> dropCollection(@RequestParam(value = "collectionName") String collectionName){
mongoTemplate.dropCollection(collectionName);
return Result.success(StatusCode.DELETE_SUCCESS.getCode(), StatusCode.DELETE_SUCCESS.getValue());
}
@ApiOperation("查询指定集合中的全部文档(Object接收)")
@GetMapping("findAllDocumentByCollectionName")
public Result<List<Object>> findAllDocumentByCollectionName(@RequestParam(value = "collectionName") String collectionName){
// 如果知道文档的属性,建议用一个实体类去接收
List<Object> list = mongoTemplate.findAll(Object.class, collectionName);
return Result.success(list);
}
@ApiOperation("查询user集合中的全部文档(具体实体类映射)")
@GetMapping("findAllDocument-user")
public Result<List<User>> findAllDocumentByCollectionName2(){
List<User> list = mongoTemplate.findAll(User.class, "user");
return Result.success(list);
}
@ApiOperation("查询myFriend集合中的全部文档(具体实体类映射)")
@GetMapping("findAllDocument-myFriend")
public Result<List<ConsumerDetail>> findAllDocumentINmyFriend(){
List<ConsumerDetail> list = mongoTemplate.findAll(ConsumerDetail.class, "myFriend");
return Result.success(list);
}
@ApiOperation("根据名称查询myFriend集合中的文档")
@GetMapping("findDocumentByConsumerName")
public Result<List<ConsumerDetail>> findDocumentByConsumerName(@RequestParam(value = "consumerName") String consumerName){
Query query = new Query(Criteria.where("consumerName").is(consumerName));
List<ConsumerDetail> list = mongoTemplate.find(query, ConsumerDetail.class, "myFriend");
return Result.success(list);
}
@ApiOperation("条件查询myFriend集合中的文档")
@GetMapping("findDocumentQuery")
public Result<List<ConsumerDetail>> findDocumentQuery(ConsumerDetailQueryForm form){
// Query 用来封装所有条件的对象
Query query = new Query();
//Criteria criteria = new Criteria();
//criteria.andOperator(
// Criteria.where("consumerName").regex(".*"+form.getConsumerName()+".*"),
// Criteria.where("gender").is(form.getGender()),
// Criteria.where("houseNum").is(form.getHouseNum()));
//query.addCriteria(criteria);
if (form.getConsumerName() != null && ! "".equals(form.getConsumerName())){
//Criteria 用来构建条件
Criteria criteria = Criteria.where("consumerName").regex(".*" + form.getConsumerName() + ".*");
query.addCriteria(criteria);
}
if (form.getGender()!=null && ! "".equals(form.getGender())){
Criteria criteria = Criteria.where("gender").is(form.getGender());
query.addCriteria(criteria);
}
if (form.getHouseNum()!=null && ! "".equals(form.getHouseNum())){
Criteria criteria = Criteria.where("houseNum").is(form.getHouseNum());
query.addCriteria(criteria);
}
List<ConsumerDetail> list = mongoTemplate.find(query, ConsumerDetail.class, "myFriend");
return Result.success(list);
}
@ApiOperation("根据id查询myFriend集合中的文档")
@GetMapping("findMyFriendDocumentById")
public Result<ConsumerDetail> findMyFriendDocumentById(@RequestParam(value = "id") String id){
//Query query = new Query(Criteria.where("_id").is(id));
//List<ConsumerDetail> list = mongoTemplate.find(query, ConsumerDetail.class, "myFriend");
ConsumerDetail consumerDetail = mongoTemplate.findById(id, ConsumerDetail.class,"myFriend");
return Result.success(consumerDetail);
}
@ApiOperation("新增文档")
@GetMapping("insertDocument")
public Result<String> insertDocument(){
User user = new User();
user.setUsername("萧敬腾");
user.setBirthday(LocalDate.of(1988,8,3));
user.setGender("男");
user.setPhoneNo("561523");
user.setAddress("台北市重庆路188号");
mongoTemplate.insert(user,"east");
return Result.success(StatusCode.CREATE_SUCCESS.getCode(), StatusCode.CREATE_SUCCESS.getValue());
}
@ApiOperation("新增文档-user集合")
@PostMapping("insertDocument-user")
public Result<String> insertDocumentUser(@RequestBody User user){
// 沒有指定集合,则默认使用实体类的名称作为集合名称,且默认转换成小驼峰
// 实体类中如果没有_id字段,则MongoDB会自动生成唯一的_id值。
mongoTemplate.insert(user);
return Result.success(StatusCode.CREATE_SUCCESS.getCode(), StatusCode.CREATE_SUCCESS.getValue());
}
@ApiOperation("新增文档-myFriend集合")
@PostMapping("insertDocument-myFriend")
public Result<String> insertDocumentMyFriend(@RequestBody ConsumerDetail consumerDetail){
// 如果实体类使用了@Document(collection = "MyFriend")注解,则会使用注解参数中设置的名称作为集合名称。不会擅改大小写。
// 如果实体类中有id字段,则最好设置成string类型,就会自动映射。
// 但是如果字段名不是id,比如cid,那么就不会自动映射了。需要我们使用注解@Id或者@MongoId,建议是@Id,其他注解可能有些问题,或者使用上有要求
// 表明该字段为主键,这样就会识别为mongodb的_id
// 当然前提是使用String字符串类型去映射,因为MongoDB默认生成的_id就是字符串类型
// 这样我们在新增的时候可以设置id值也可以让mongoDB自动生成。
// ps(这里实体类名叫ConsumerDetail,映射的集合叫myFriend,这里只是演示。实际建议他们名称一致)
mongoTemplate.insert(consumerDetail);
return Result.success(StatusCode.CREATE_SUCCESS.getCode(), StatusCode.CREATE_SUCCESS.getValue());
}
@ApiOperation("新增文档-foodDetail集合(自定义主键规则)")
@PostMapping("insertDocument-foodDetail")
public Result<StringBuilder> insertDocumentFoodDetail(){
StringBuilder result = new StringBuilder();
result.append("倘若我们不希望使用MongoDB默认规则生成的主键 \n" +
" 比如希望主键自增,怎么办呢? \n" +
"由于MongoDB本身并不维护自增ID,因此只能利用MongoDB的原子性通过findAndModify自增1来实现 \n " +
"所以需要我们自定义规则来生成id。\n " +
"比如自定义一个自增注解,表明此ID需要自增 \n " +
"然后监听MongoDB-data的保存操作,在保存前进行ID的替换\n" +
"比较麻烦,这里就不掩饰了,感兴趣的可以自行尝试");
return Result.success(result);
}
@ApiOperation("修改文档-myFriend集合")
@PostMapping("updateDocument-myFriend")
public Result<StringBuilder> updateDocumentMyFriend(ConsumerDetail consumerDetail){
// 参数校验
if (consumerDetail.getCid() == null){
Result.error(-1,"请传递id参数");
}
// 构建查询条件
Query query = new Query();
query.addCriteria(Criteria.where("_id").is(consumerDetail.getCid()));
// 设置更新字段
Update update = new Update();
update.set("consumerName",consumerDetail.getConsumerName());
update.set("gender",consumerDetail.getGender());
update.set("birthday",consumerDetail.getBirthday());
update.set("phoneNo",consumerDetail.getPhoneNo());
update.set("houseNum",consumerDetail.getHouseNum());
update.set("remark",consumerDetail.getRemark());
// 调用upsert方法进行修改
// 以下三个重载方法都可以。加上集合名称是为了防止你修改了映射集合名称。
// 所以,保险起见,最好的方式是使用第三个方法。
// mongoTemplate.upsert(query,update,ConsumerDetail.class);
// mongoTemplate.upsert(query,update,"myFriend");
mongoTemplate.upsert(query,update,ConsumerDetail.class,"myFriend");
return Result.success();
}
@ApiOperation("删除文档-myFriend集合")
@PostMapping("removeDocument-myFriend")
public Result<StringBuilder> removeDocumentMyFriend(@RequestParam("id") String id){
//mongoTemplate.remove(new Query(Criteria.where("_id").is(id)),ConsumerDetail.class);
//mongoTemplate.remove(new Query(Criteria.where("_id").is(id)),"myFriend");
mongoTemplate.remove(new Query(Criteria.where("_id").is(id)),ConsumerDetail.class,"myFriend");
return Result.success(StatusCode.DELETE_SUCCESS.getCode(), StatusCode.DELETE_SUCCESS.getValue());
}
@ApiOperation("查询myFriend集合中的文档总数")
@GetMapping("findMyFriendDocumentCount")
public Result<Long> findMyFriendDocumentCount(){
// 其实该方法可以根据条件查询,查询符合条件的文档记录总数,只不过这里query未设置条件而已
// 当然了,和修改删除一样,它也有几个重载方法,保险期间用如下这个
Query query = new Query();
long count = mongoTemplate.count(query, ConsumerDetail.class, "myFriend");
return Result.success(count);
}
@ApiOperation("分页查询myFriend集合中的全部文档")
@GetMapping("findMyFriendAllDocumentPage")
public Result<PageImpl<ConsumerDetail>> findMyFriendAllDocumentPage(Integer pageNum,Integer pageSize){
// 查询方法还是它find()方法,只是查询条件中封装分页对象
Query query = new Query();
query.with(Sort.by(Sort.Order.desc("birthday"))); // 按照生日降序排列
Pageable pageable = PageRequest.of(pageNum - 1, pageSize);
query.with(pageable); // 分页查询
List<ConsumerDetail> list = mongoTemplate.find(query, ConsumerDetail.class, "myFriend");
return Result.success(new PageImpl<>(list));
}
}
7.5 部分效果展示
就展示到这儿,需要的可以将代码直接复制到自己的项目中进行演示。
当然也可以自己写。不过一定要熟悉一下,毕竟今后是用代码打交道的~