一、MongoDB简介
1、什么是MongoDB
MongoDB 是一个跨平台的,面向文档的数据库,是当前 NoSQL 数据库产品中最热门的一种。它介于关系数据库和非关系数据库之间,是非关系数据库当中功能最丰富,最像关系数据库的产品。它支持的数据结构非常松散,是类似 JSON 的 BSON 格式,因此可以存储比较复杂的数据类型。
2、MongoDB特点
MongoDB 最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。它是一个面向集合的,模式自由的文档型数据库。具体特点总结如下:
(1)、面向集合存储,易于存储对象类型的数据
(2)、模式自由
(3)、支持动态查询
(4)、支持完全索引,包含内部对象
(5)、支持复制和故障恢复
(6)、使用高效的二进制数据存储,包括大型对象(如视频等)
(7)、自动处理碎片,以支持云计算层次的扩展性
(8)、支持 Python,PHP,Ruby,Java,C,C#,Javascript,Perl 及 C++语言的驱动程序,社区中也提供了对 Erlang 及.NET 等平台的驱动程序
(9)、 文件存储格式为 BSON(一种 JSON 的扩展)
3、MongoDB的体系结构
MongoDB 的逻辑结构是一种层次结构。主要由:文档(document)、集合(collection)、数据库(database) 这三部分组成的。逻辑结构是面向用户的,用户使用 MongoDB 开发应用程序使用的就是逻辑结构。
(1)MongoDB 的文档(document),相当于关系数据库中的一行记录。
(2)多个文档组成一个集合(collection),相当于关系数据库的表。
(3)多个集合(collection),逻辑上组织在一起,就是数据库(database)。
(4)一个 MongoDB 实例支持多个数据库(database)。
文档(document)、集合(collection)、数据库(database)的层次结构如下图:
MongoDB与MySQL数据库逻辑结构概念对比如下:
4、MongoDB的数据类型
null:用于表示空值或者不存在的字段,{“x”:null}
布尔型:布尔类型有两个值true和false,{“x”:true}
数值:shell默认使用64为浮点型数值。{“x”:3.14}或{“x”:3}。对于整型值,可以使用NumberInt(4字节符号整数)或NumberLong(8字节符号整数),{“x”:NumberInt(“3”)}{“x”:NumberLong(“3”)}
字符串:UTF-8字符串都可以表示为字符串类型的数据,{“x”:“呵呵”}
日期:日期被存储为自新纪元依赖经过的毫秒数,不存储时区,{“x”:new Date()}
数组:数据列表或数据集可以表示为数组,{“x”: [“a“,“b”,”c”]}
内嵌文档:文档可以嵌套其他文档,被嵌套的文档作为值来处理,{“x”:{“y”:3 }}
对象Id:对象id是一个12字节的字符串,是文档的唯一标识,{“x”: objectId() }
二进制数据:二进制数据是一个任意字节的字符串。它不能直接在shell中使用。如果要将非utf-字符保存到数据库中,二进制数据是唯一的方式。
代码:查询和文档中可以包括任何JavaScript代码,{“x”:function(){/…/}}
二、MongoDB的安装与使用
1、Windows下MongoDB的安装及配置
MongoDB下载路径:https://download.csdn.net/download/wingzhezhe/10534774
(1)、配置环境变量
(2)、启动MongoDB服务
注意:启动之前需要创建数据目录
(3)、连接MongoDB
2、Docker中安装MongoDB
(1)、拉取镜像
docker pull mongo
(2)、启动守护式容器
docker run -di --name=tensquare_mongo -p 27017:27017 mongo
(3)、远程连接MongoDB数据库
3、MongoDB常用命令
(1)、选择和创建数据库
语法: use 数据库名称
说明:如果数据库不存在,会默认创建数据库
(2)、插入与查询文档
插入文档的语法:
db.集合名称.insert(数据);
查询集合的语法:
-- 查询所有
db.集合名称.find()
-- 带条件查询
db.集合名称.find({字段名:条件值})
-- 查询符合条件的第一条数据
db.集合名称.findOne({字段名:条件值})
-- 指定返回结果的数量
db.集合名称.find().limit(3)
注意:每条文档会有一个叫_id的字段,这个相当于我们原来关系数据库中表的主键,当你在插入文档记录时没有指定该字段,MongoDB会自动创建,其类型是ObjectID类型。如果我们在插入文档记录时指定该字段也可以,其类型可以是ObjectID类型,也可以是MongoDB支持的任意类型。
(3)、修改与删除文档
修改文档的语法:
-- 修改文档,此种方式修改后,没有修改的字段都会删除
db.集合名称.update({条件字段:条件值}, {要修改的字段:修改后的数据值})
-- 使用 $set 修改器来修改,保证只修改要指定的字段,其它字段保持原值
db.集合名称.update({条件字段:条件值}, {$set:{要修改的字段:修改后的数据值}})
删除文档的语法:
-- 删除指定文档
db.集合名称.remove({条件字段:条件值})
-- 删除所有文档
db.集合名称.remove({})
(4)、统计条数
统计条数语法:
db.spit.count()
(5)、模糊查询
MongoDB中的模糊查询是通过正则表达式来实现的,格式为:
-- 模糊查询,条件是正则表达式
db.spit.find({条件字段:/内容/})
(6)、大于 小于 不等于
-- 大于: field > value
db.集合名称.find({ "field" : { $gt: value }})
-- 小于: field < value
db.集合名称.find({ "field" : { $lt: value }})
-- 大于等于: field >= value
db.集合名称.find({ "field" : { $gte: value }})
-- 小于等于: field <= value
db.集合名称.find({ "field" : { $lte: value }})
-- 不等于: field != value
db.集合名称.find({ "field" : { $ne: value }})
(7)、包含于不包含
包含使用$in操作符,不包含使用$nin操作符。
(8)、条件连接
需要查询同时满足两个以上条件,需要使用$and操作符将条件进行关联。(相当于SQL的and),如果两个以上条件之间是或者的关系,我们使用 $or 操作符进行关联,与前面 and的使用方式相同,条件连接的格式如下:
-- 并列关系
$and:[条件1, 条件2]
-- 与关系
$or:[条件1, 条件2]
(9)、列值增长
实现对某列值在原有值的基础上进行增加或减少,可以使用 $inc 运算符来实现:
db.spit.update({_id:"2"},{$inc:{visits:NumberInt(1)}} )
三、Java操作MongoDB
1、创建maven project,引入MongoDB驱动jar包坐标
<dependencies>
<!-- 引入MongoDB驱动依赖 -->
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver</artifactId>
<version>3.6.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
2、创建测试类
package com.mongodb.test;
import com.mongodb.BasicDBObject;
import com.mongodb.MongoClient;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
public class MongoDBTest {
/**
* 查询所有
*/
@Test
public void testFindAll() {
//创建连接对象
MongoClient client = new MongoClient("192.168.37.133");
//打开数据库
MongoDatabase spitdb = client.getDatabase("spitdb");
//获取集合
MongoCollection<Document> collection = spitdb.getCollection("spit");
//获取文档集合
FindIterable<Document> documents = collection.find();
//遍历文档集合,获取内容
for (Document doc : documents) {
System.out.println("吐槽内容" + doc.getString("content"));
System.out.println("用户id" + doc.getString("userid"));
System.out.println("用户昵称" + doc.getString("nickname"));
System.out.println("浏览量" + doc.getInteger("visits"));
System.out.println("-----------------------------------------------");
}
//释放连接
client.close();
}
/**
* 带条件查询
*/
@Test
public void testFindBySpec() {
//创建连接对象
MongoClient client = new MongoClient("192.168.37.133");
//打开数据库
MongoDatabase spitdb = client.getDatabase("spitdb");
//获取集合
MongoCollection<Document> collection = spitdb.getCollection("spit");
//封装查询条件
BasicDBObject bson = new BasicDBObject("visits", new BasicDBObject("$gte", 903));
//获取文档集合
FindIterable<Document> documents = collection.find(bson);
//遍历文档集合,获取内容
for (Document doc : documents) {
System.out.println("吐槽内容" + doc.getString("content"));
System.out.println("用户id" + doc.getString("userid"));
System.out.println("用户昵称" + doc.getString("nickname"));
System.out.println("浏览量" + doc.getInteger("visits"));
System.out.println("-----------------------------------------------");
}
//释放连接
client.close();
}
/**
* 插入一条记录
*/
@Test
public void testInsert(){
//创建连接对象
MongoClient client = new MongoClient("192.168.37.133");
//打开数据库
MongoDatabase spitdb = client.getDatabase("spitdb");
//获取集合
MongoCollection<Document> collection = spitdb.getCollection("spit");
//封装文档对象
Map map = new HashMap();
map.put("content", "我要吐槽");
map.put("userid", "1044");
map.put("nickname", "李子明");
map.put("visits", 1580);
Document doc = new Document(map);
//插入数据
collection.insertOne(doc);
//释放连接
client.close();
}
}
3、spirngboot操作MongoDB的jar包
SpringDataMongoDB是spirngdata家族成员之一,用于操作MongoDb的持久层框架,封装了底层的mongodb-driver。
四、吐槽微服务功能
1、搭建吐槽微服务环境
(1)、创建Maven Module
(2)、pom.xml加入jar包坐标
<dependencies>
<!-- 加入MongoDB依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<!-- 加入common基础功能依赖 -->
<dependency>
<groupId>com.scf</groupId>
<artifactId>scf_common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- 加入springdataRedis坐标 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
(3)、加入配置文件和启动类
application.yml
server:
port: 9006
spring:
application:
name: scf-spit
data:
mongodb:
host: 192.168.37.133
database: spitdb
redis:
host: 192.168.37.133
port: 6379
SpitApplication.java
package com.scf.spit;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import util.IdWorker;
@SpringBootApplication
public class SpitApplication {
public static void main(String[] args) {
SpringApplication.run(SpitApplication.class, args);
}
@Bean
public IdWorker idWorker() {
return new IdWorker(1, 1);
}
}
(4)、编写吐槽实体类和数据访问层架构
Spit.java
package com.scf.spit.pojo;
import java.util.Date;
/**
* 吐槽实体类
*/
public class Spit {
private String _id;//主键
private String content;//吐槽内容
private Date publishtime;//发布日期
private String userid;//发布人ID
private String nickname;//昵称
private Integer visits;//浏览量
private Integer thumbup;//点赞数
private Integer share;//分享数
private Integer comment;//回复数
private String state;//状态
private String parentid;//上级ID
public Spit() {
}
SpitDao.java
package com.scf.spit.dao;
import com.scf.spit.pojo.Spit;
import org.springframework.data.mongodb.repository.MongoRepository;
/**
* 吐槽功能的数据访问层接口
*/
public interface SpitDao extends MongoRepository<Spit, String> {
}
2、吐槽微服务基础CRUD功能实现
SpitService.java
package com.scf.spit.service;
import com.scf.spit.dao.SpitDao;
import com.scf.spit.pojo.Spit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import util.IdWorker;
import java.util.List;
/**
* 吐槽服务的业务路基层
*/
@Service
public class SpitService {
@Autowired
private SpitDao spitDao;
@Autowired
private IdWorker idWorker;
/***
* 查询全部数据
* @return
*/
public List<Spit> findAll(){
return spitDao.findAll();
}
/**
* 根据ID查询数据
* @param id
* @return
*/
public Spit findById(String id){
return spitDao.findById(id).get();
}
/**
* 增加吐槽
* @param spit
*/
public void add(Spit spit){
spit.set_id(idWorker.nextId()+"");
spitDao.save(spit);
}
/**
* 修改吐槽
* @param spit
*/
public void update(Spit spit){
spitDao.save(spit);
}
/**
* 删除吐槽
* @param id
*/
public void deleteById(String id){
spitDao.deleteById(id);
}
}
SpitController.java
package com.scf.spit.controller;
import com.scf.spit.pojo.Spit;
import com.scf.spit.service.SpitService;
import entity.Result;
import entity.StatusCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@CrossOrigin //跨域注解
@RequestMapping("/spit")
public class SpitController {
@Autowired
private SpitService spitService;
/**
* 查询全部记录
* @return
*/
@RequestMapping(method = RequestMethod.GET)
public Result findAll(){
List<Spit> list = spitService.findAll();
return new Result(true, StatusCode.OK,"查询成功",list);
}
/**
* 根据ID查询吐槽
* @param id
* @return
*/
@RequestMapping( value="/{id}" ,method = RequestMethod.GET)
public Result findById(@PathVariable String id){
Spit spit = spitService.findById(id);
return new Result(true, StatusCode.OK,"查询成功",spit);
}
/**
* 增加吐槽
* @param spit
* @return
*/
@RequestMapping( method = RequestMethod.POST)
public Result add( @RequestBody Spit spit ){
spitService.add(spit);
return new Result(true,StatusCode.OK,"增加成功");
}
/**
* 修改吐槽
* @param spit
* @param id
* @return
*/
@RequestMapping( value ="/{id}" ,method = RequestMethod.PUT)
public Result update( @RequestBody Spit spit ,@PathVariable String id){
spit.set_id(id);
spitService.update(spit);
return new Result(true,StatusCode.OK,"修改成功");
}
/**
* 删除吐槽
* @param id
* @return
*/
@RequestMapping( value ="/{id}" ,method = RequestMethod.DELETE)
public Result deleteById(@PathVariable String id){
spitService.deleteById(id);
return new Result(true,StatusCode.OK,"删除成功");
}
}
3、根据父类id查询吐槽列表,吐槽点赞,发布吐槽功能的实现
SpitDao.java
/**
* 根据上级id查询吐槽列表
* @param parentid
* @param pageable
* @return
*/
public Page<Spit> findByParentid(String parentid, Pageable pageable);
SpitService.java
/**
* 根据上级ID查询吐槽列表
*
* @param parentId
* @param page
* @param size
* @return
*/
public Page<Spit> findByParentid(String parentId, int page, int size) {
PageRequest pageRequest = PageRequest.of(page - 1, size);
return spitDao.findByParentid(parentId, pageRequest);
}
@Autowired
private MongoTemplate mongoTemplate;
/**
* 吐槽点赞功能
*
* @param id
*/
public void updateThumbup(String id) {
//创建查询对象
Query query = new Query();
//封装查询条件
query.addCriteria(Criteria.where("_id").is(id));
//创建修改对象
Update update = new Update();
//设置修改内容
update.inc("thumbup", 1);
//执行修改操作
mongoTemplate.updateFirst(query, update, "spit");
}
/**
* 发布吐槽
*
* @param spit
*/
public void add(Spit spit) {
spit.set_id(idWorker.nextId() + "");
spit.setPublishtime(new Date());
spit.setVisits(0); //浏览量
spit.setShare(0); //分享数
spit.setThumbup(0); //点赞数
spit.setComment(0); //回复数
spit.setState("1"); //状态
if(spit.getParentid() != null && !"".equals(spit.getParentid())){
//如果存在上级,设置上级回复数 +1
Query query = new Query();
query.addCriteria(Criteria.where("_id").is(spit.getParentid()));
Update update = new Update();
update.inc("comment", 1);
mongoTemplate.updateFirst(query, update, "spit");
}
spitDao.save(spit);
}
SpitController.java
/**
* 根据上级ID查询吐槽列表
* @param parentId
* @param page
* @param size
* @return
*/
@RequestMapping(value = "/comment/{parentId}/{page}/{size}", method = RequestMethod.GET)
public Result findByParentId(@PathVariable String parentId, @PathVariable int page, @PathVariable int size) {
Page<Spit> pageList = spitService.findByParentid(parentId, page, size);
PageResult<Spit> pageResult = new PageResult<>(pageList.getTotalElements(), pageList.getContent());
return new Result(true, StatusCode.OK, "查询成功", pageResult);
}
/**
* 吐槽点赞
* @param id
* @return
*/
@RequestMapping(value = "/thumbup/{id}", method = RequestMethod.PUT)
public Result updateThumbup(@PathVariable String id){
spitService.updateThumbup(id);
return new Result(true, StatusCode.OK, "点赞成功");
}
五、文章评论功能
1、表结构分析
2、新增评论功能
(1)、scf_article项目中的pom.xml中加入MongoDB依赖
<!-- 加入MongoDB依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
(2)、application.yml中加入MongoDB配置
(3)、创建评论实体类
package com.scf.article.pojo;
import javax.persistence.Id;
import java.util.Date;
public class Comment {
@Id
private String id;
private String articleid;
private String content;
private String userid;
private String parentid;
private Date publishdate;
getter/setter
}
(4)、数据访问层接口
package com.scf.article.dao;
import com.scf.article.pojo.Comment;
import org.springframework.data.mongodb.repository.MongoRepository;
/**
* 评论的数据访问层接口
*/
public interface CommentDao extends MongoRepository<Comment, String> {
}
(5)、业务逻辑层代码
package com.scf.article.service;
import com.scf.article.dao.CommentDao;
import com.scf.article.pojo.Comment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import util.IdWorker;
@Service
public class CommentService {
@Autowired
private CommentDao commentDao;
@Autowired
private IdWorker idWorker;
/**
* 新增评论
* @param comment
*/
public void add(Comment comment){
comment.setId(idWorker.nextId() + "");
commentDao.save(comment);
}
}
(6)、web层代码
package com.scf.article.controller;
import com.scf.article.pojo.Comment;
import com.scf.article.service.CommentService;
import entity.Result;
import entity.StatusCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@CrossOrigin
@RequestMapping(value = "/comment")
public class CommentController {
@Autowired
private CommentService commentService;
@RequestMapping(method = RequestMethod.POST)
public Result save(@RequestBody Comment comment){
commentService.add(comment);
return new Result(true, StatusCode.OK, "提交成功");
}
}
3、根据文章ID查询评论列表
CommentDao.java
/**
* 根据文章ID查询品论列表
* @param atticleid
* @return
*/
public List<Comment> findByArticleid(String atticleid);
CommentService.java
/**
* 根据文章ID获取评论列表
* @param articleid
* @return
*/
public List<Comment> findByArticleId(String articleid){
return commentDao.findByArticleid(articleid);
}
CommentController.java
/**
* 根据文章ID获取评论列表
* @param articleid
* @return
*/
@RequestMapping(value = "/article/{articleid}", method = RequestMethod.GET)
public Result findByArticleId(@PathVariable String articleid){
List<Comment> commentList = commentService.findByArticleId(articleid);
return new Result(true, StatusCode.OK, "查询成功", commentList);
}