MongoDB 简介
对于这样的数据,我们更适合使用 MongoDB来实现数据的存储
- 数据量大
- 写入操作频繁
- 价值较低
比如
- 评论信息
- 吐槽信息
什么是 MongoDB
MongoDB 是一个跨平台的,面向文档的数据库,是当前 NoSQL 数据库产品中
最热门的一种。$\color{red}{它介于关系数据库和非关系数据库之间,是非关系数据库当中功
能最丰富,最像关系数据库的产品。}$它支持的数据结构非常松散,是类似 JSON 的
BSON 格式,因此可以存储比较复杂的数据类型。
MongoDB 的官方网站地址是: http://www.mongodb.org/
MongoDB 特点
MongoDB 最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语
言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。
它是一个面向集合的,模式自由的文档型数据库。
具体特点总结如下:
- 面向集合存储,易于存储对象类型的数据
- 模式自由
- 支持动态查询
- 支持完全索引,包含内部对象
- 支持复制和故障恢复
- 使用高效的二进制数据存储,包括大型对象(如视频等)
- 自动处理碎片,以支持云计算层次的扩展性
- 支持 Python,PHP,Ruby,Java,C,C#,Javascript,Perl 及 C++语言的驱动程序,社区中也提供了对 Erlang 及.NET 等平台的驱动程序
- 文件存储格式为 BSON(一种 JSON 的扩展)
MongoDB 体系结构
MongoDB 的逻辑结构是一种层次结构。主要由:
文档(document)、集合(collection)、数据库(database)这三部分组成的。逻辑结构
是面向用户的,用户使用 MongoDB 开发应用程序使用的就是逻辑结构。
- MongoDB 的文档(document),相当于关系数据库中的一行记录。
- 多个文档组成一个集合(collection),相当于关系数据库的表。
- 多个集合(collection),逻辑上组织在一起,就是数据库(database)。
- 一个 MongoDB 实例支持多个数据库(database)。
文档(document)、集合(collection)、数据库(database)的层次结构如下图:
数据类型
基本数据类型
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()}
正则表达式:
查询时,使用正则表达式作为限定条件,语法与 JavaScript 的正则表达式相同,
{“x”:/[abc]/}
数组:
数据列表或数据集可以表示为数组,{“x”: [“a“,“b”,”c”]}
内嵌文档:
文档可以嵌套其他文档,被嵌套的文档作为值来处理,{“x”:{“y”:3 }}
对象 Id:
对象 id 是一个 12 字节的字符串,是文档的唯一标识,{“x”: objectId() }
二进制数据:
二进制数据是一个任意字节的字符串。它不能直接在 shell 中使用。如果要将非 utf-字符保存到数据库中,二进制数据是唯一的方式。
代码:
查询和文档中可以包括任何 JavaScript 代码,{“x”:function(){/…/}}
MongoDB 安装与启动
window 安装 MongoDB
双击“mongodb-win32-x86_64-2008plusssl-3.2.10-signed.msi” 按照
提示步骤安装即可。安装完成后,软件会安装在 C:\ProgramFiles\MongoDB 目录中。
我们要启动的服务程序就是 C:\Program Files\MongoDB\Server\3.2\bin 目录下的 mongod.exe,
为了方便我们每次启动,我将 C:\ProgramFiles\MongoDB\Server\3.2\bin 设置到环境变量 path
中。
启动
首先打开命令提示符,创建一个用于存放数据的目录
启动服务,并指定数据存放目录
1
|
mongod --dbpath=d:\data
|
我们在启动信息中可以看到,mongoDB 的默认端口是 27017
如果我们想改变默认的启动端口,可以通过–port 来指定端口
在命令提示符输入以下命令即可完成登陆
退出 mongodb
Docker 安装 MongoDB
在宿主机创建 mongo 容器
1
|
docker run -di --name=mymMngo -p 27017:27017 --restart=awlays mongo
|
远程登陆
实例
创建数据库
1
2
3
4
5
|
> use runoob
switched to db runoob
> db
runoob
>
|
如果你想查看所有数据库,可以使用 show dbs 命令:
1
2
3
4
5
|
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
>
|
可以看到,我们刚创建的数据库 runoob 并不在数据库的列表中, 要显示它,我们需要向 runoob 数据库插入一些数据。
1
2
3
4
5
6
7
|
> db.runoob.insert({"name":"菜鸟教程"})
WriteResult({ "nInserted" : 1 })
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
runoob 0.000GB
|
MongoDB 中默认的数据库为 test,如果你没有创建新的数据库,集合将存放在 test 数据库中。
注意: 在 MongoDB 中,集合只有在内容插入后才会创建! 就是说,创建集合(数据表)后要再插入一个文档(记录),集合才会真正创建。向一个集合插入数据,会帮你创建一个与集合名字一样并后面加上db的数据库
插入数据语句
1
|
db.spit.insert({_id:"1",username:"黄思聪",age:"22"})
|
$\color{red}{当你执行上面的插入语句之后,就会帮你创建一个数据库为spitdb的数据库,里面有一个集合(数据表)spit}$
查询数据语句
这里你会发现每条文档会有一个叫_id 的字段,这个相当于我们原来关系数据库中表的主
键,当你在插入文档记录时没有指定该字段,MongoDB 会自动创建,其类型是 ObjectID
类型。如果我们在插入文档记录时指定该字段也可以,其类型可以是 ObjectID 类型,也
可以是 MongoDB 支持的任意类型。
条件查询
如果我想按一定条件来查询,比如我想查询 userid 为 1013 的记录,怎么办?很简单!只
要在 find()中添加参数即可,参数也是 json 格式,如下:
1
|
db.spit.find({userid:'1013'})
|
如果你只需要返回符合条件的第一条数据,我们可以使用 findOne 命令来实现
1
|
db.spit.findOne({userid:'1013'})
|
如果你想返回指定条数的记录,可以在 find 方法后调用 limit 来返回结果,例如:
1
|
db.spit.find().limit(3)
|
修改和删除文档
修改文档的语法结构:
1
|
db.集合名称.update(条件,修改后的数据)
|
如果我们想修改_id 为 1 的记录,浏览量为 1000,输入以下语句:
1
|
db.spit.update({_id:"1"},{visits:NumberInt(1000)})
|
执行后,我们会发现,这条文档除了 visits 字段其它字段都不见了,为了解决这个问题,我
们需要使用修改器$set 来实现,命令如下:
1
|
db.spit.update({_id:"2"},{$set:{visits:NumberInt(2000)}})
|
这样就 OK 啦。
删除文档的语法结构:
以下语句可以将数据全部删除,请慎用
如果删除 visits=1000 的记录,输入以下语句
1
|
db.spit.remove({visits:1000})
|
统计条数
统计条数
统计记录条件使用 count()方法。以下语句统计 spit 集合的记录数
如果按条件统计 ,例如:统计 userid 为 1013 的记录条数
1
|
db.spit.count({userid:"1013"})
|
模糊查询
MongoDB 的模糊查询是通过正则表达式的方式实现的。格式为:
/模糊查询字符串/
例如,查询流量
1
|
db.spit.find({content:/流量/})
|
如果要查询以“加班”开头的,代码如下:
1
|
db.spit.find({content:/^加班/})
|
大于 小于 不等于
<, <=, >, >= 这个操作符也是很常用的,格式如下:
1
2
3
4
5
|
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 }}) // 不等于: field != value
|
示例:查询吐槽浏览量大于 1000 的记录
1
|
db.spit.find({visits:{$gt:1000}})
|
包含与不包含
包含使用$in 操作符。
示例:查询吐槽集合中 userid 字段包含 1013 和 1014 的文档
1
|
db.spit.find({userid:{$in:["1013","1014"]}})
|
不包含使用$nin 操作符。
示例:查询吐槽集合中 userid 字段不包含 1013 和 1014 的文档
1
|
db.spit.find({userid:{$nin:["1013","1014"]}})
|
条件连接
我们如果需要查询同时满足两个以上条件,需要使用$and 操作符将条件进行关联。(相当
于 SQL 的 and)
格式为:
示例:查询吐槽集合中 visits 大于等于 1000 并且小于 2000 的文档
1
|
db.spit.find({$and:[ {visits:{$gte:1000}} ,{visits:{$lt:2000} }]})
|
如果两个以上条件之间是或者的关系,我们使用 操作符进行关联,与前面 and 的使用方式
相同
格式为:
示例:查询吐槽集合中 userid 为 1013,或者浏览量小于 2000 的文档记录
1
|
db.spit.find({$or:[ {userid:"1013"} ,{visits:{$lt:2000} }]})
|
列值增长
如果我们想实现对某列值在原有值的基础上进行增加或减少,可以使用$inc 运算符来实现
1
|
db.spit.update({_id:"2"},{$inc:{visits:NumberInt(1)}} )
|
Java 操作 MongoDB
MongoDB-Driver
mongodb-driver 是 mongo 官方推出的 java 连接 mongoDB 的驱动包,相当于 JDBC
驱动。我们通过一个入门的案例来了解 mongodb-driver 的基本使用
1
2
3
4
5
|
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver</artifactId>
<version>3.6.3</version>
</dependency>
|
工具类
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
|
public class GetSpit {
//创建连接
private static MongoClient mongoClient = null;
private static MongoDatabase spitdb = null;
private static MongoCollection<Document> spit = null;
private GetSpit() {
}
static {
mongoClient = new MongoClient("127.0.0.1");
spitdb = mongoClient.getDatabase("spitdb");
spit = spitdb.getCollection("spit");
}
public static MongoCollection<Document> getDoc() {
return spit;
}
public static MongoClient getMongoClient(){
return mongoClient;
}
}
|
添加数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
/**
* 插入数据
*/
@Test
public void addSpit(){
MongoCollection<Document> spit = GetSpit.getDoc();
//新建一个容器存放数据
Map<String,Object> map= new HashMap();
map.put("_id","5");
map.put("content","关于java的那点事");
map.put("userid","1001");
map.put("visits",678);
map.put("publishtime",new Date());
Document document = new Document(map);
spit.insertOne(document);
GetSpit.getMongoClient().close();
}
|
查询全部数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
/**
* 查询全部
*/
@Test
public void selectAllSipt(){
MongoCollection<Document> spit = GetSpit.getDoc();
//获取集合数据
FindIterable<Document> documents = spit.find();
for(Document document:documents){
System.out.println("内容:"+document.getString("content"));
System.out.println("用户id:"+document.getString("userid"));
System.out.println("点赞数:"+document.getInteger("visits"));
System.out.println("时间:"+document.getDate("publishtime"));
}
GetSpit.getMongoClient().close();
}
|
条件查询数据
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
|
/***
* 条件查询
*/
@Test
public void findByUserName(){
MongoCollection<Document> spit = GetSpit.getDoc();
//查询visits(访问量)等于
// BasicDBObject basicDBObject = new BasicDBObject("visits", 456);
//查询访问量大于456
// BasicDBObject basicDBObject = new BasicDBObject("visits", new BasicDBObject("$gt",456));
//查询访问量小于456
// BasicDBObject basicDBObject = new BasicDBObject("visits", new BasicDBObject("$lt",456));
//查询访问量不等于456
// BasicDBObject basicDBObject = new BasicDBObject("visits", new BasicDBObject("$ne",456));
//查询访问量小于等于456
// BasicDBObject basicDBObject = new BasicDBObject("visits", new BasicDBObject("$lte",456));
//查询访问量大于等于456
// BasicDBObject basicDBObject = new BasicDBObject("visits", new BasicDBObject("$gte",456));
int[] a= new int[]{123,678};
//查询访问量包含123,678
// BasicDBObject basicDBObject = new BasicDBObject("visits", new BasicDBObject("$in",a));
//查询访问量不包含123,678
// BasicDBObject basicDBObject = new BasicDBObject("visits", new BasicDBObject("$nin",a));
BasicDBObject basicDBObject = new BasicDBObject();
//先放集合
BasicDBList basicDBList = new BasicDBList();
basicDBList.add(new BasicDBObject("visits", 456));
basicDBList.add(new BasicDBObject("content", "关于java那点事"));
//条件连接and
// basicDBObject.put("$and",basicDBList);
//条件连接or
basicDBObject.put("$or",basicDBList);
FindIterable<Document> documents = spit.find(basicDBObject);
for(Document document:documents){
System.out.println("内容:"+document.getString("content"));
System.out.println("用户id:"+document.getString("userid"));
System.out.println("点赞数:"+document.getInteger("visits"));
System.out.println("时间:"+document.getDate("publishtime"));
}
GetSpit.getMongoClient().close();
}
|
SpringDataMongoDB
SpringData 家族成员之一,用于操作 MongoDb 的持久层框架,封装了底层的 mongodbdriver。
官网主页: https://projects.spring.io/spring-data-mongodb/
运用SpringDataMongoDB框架进行开发
pom文件
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>com.tensquare</groupId>
<artifactId>tensquare_common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
1
2
3
4
5
6
7
8
9
10
11
|
server:
port: 9006
spring:
application:
name: tensquare‐spit #指定服务名
data:
mongodb:
host: 192.168.2.2
database: spitdb
redis:
host: 192.168.2.2
|
实体类
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
@Document(collection = "spit")
public class Spit implements Serializable {
@Id
private String id;
private String content;
private Date publishtime;
private String userid;
private String nickname;
private Integer visits;
private Integer thumbup;
private Integer share;
private Integer comment;
private String state;
private String parentid; //父 id
public Spit(String id, String content, Date publishtime, String userid, String nickname, Integer visits, Integer thumbup, Integer share, Integer comment, String state, String parentid) {
this.id = id;
this.content = content;
this.publishtime = publishtime;
this.userid = userid;
this.nickname = nickname;
this.visits = visits;
this.thumbup = thumbup;
this.share = share;
this.comment = comment;
this.state = state;
this.parentid = parentid;
}
public Spit() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Date getPublishtime() {
return publishtime;
}
public void setPublishtime(Date publishtime) {
this.publishtime = publishtime;
}
public String getUserid() {
return userid;
}
public void setUserid(String userid) {
this.userid = userid;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public Integer getVisits() {
return visits;
}
public void setVisits(Integer visits) {
this.visits = visits;
}
public Integer getThumbup() {
return thumbup;
}
public void setThumbup(Integer thumbup) {
this.thumbup = thumbup;
}
public Integer getShare() {
return share;
}
public void setShare(Integer share) {
this.share = share;
}
public Integer getComment() {
return comment;
}
public void setComment(Integer comment) {
this.comment = comment;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getParentid() {
return parentid;
}
public void setParentid(String parentid) {
this.parentid = parentid;
}
}
|
dao
1
2
3
|
public interface SpitDao extends MongoRepository<Spit,String> {
public Page<Spit> findByParentid(String parentid,Pageable spitPage);
}
|
service
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
@Service
public class SpitService {
@Autowired
private SpitDao spitDao;
@Autowired
private IdWorker idWorker;
@Autowired
private MongoTemplate mongoTemplate;
/**
* 查询全部
* @return
*/
public List<Spit> selectAll(){
return spitDao.findAll();
}
/**
* 添加
* @param spit
*/
public void addSpit(Spit spit){
spit.setId(idWorker.nextId()+"");
spitDao.save(spit);
}
/**
* 根据id进行查询
* @param id
* @return
*/
public Spit selectByIdSpit(String id){
return spitDao.findById(id).get();
}
@Transactional
public void updateSpit(Spit spit,String id){
spit.setId(id);
spitDao.save(spit);
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 id
*/
public void deleteByIdSpit(String id){
spitDao.deleteById(id);
}
public Page<Spit> selectByParentIdSpit(String parentid,Integer page,Integer size){
PageRequest spitPage = PageRequest.of(page-1, size);
return spitDao.findByParentid(parentid,spitPage);
}
/**
* 点赞
* @param id
*/
@Transactional
public void updateThumbupBySpitId(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");
}
/*@Transactional
public void updateNoThumbupBySpitId(String id){
Query query = new Query();
Field fields = query.fields();
Document document = query.getFieldsObject();
Integer thumbup = document.getInteger("thumbup");
query.addCriteria(Criteria.where("_id").is(id));
Update update = new Update();
update.inc("thumbup",thumbup);
mongoTemplate.updateFirst(query,update,"spit");
}*/
}
|
controller
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
@RestController
@CrossOrigin
@RequestMapping("spit")
public class SpitController {
@Autowired
private SpitService spitService;
@Autowired
private RedisTemplate redisTemplate;
/**
* 查询全部数据
* @return
*/
@RequestMapping(method = RequestMethod.GET)
public Result selectAll() {
return new Result(true, StatusCode.OK, "查询全部", spitService.selectAll());
}
/**
* 添加
* @param spit
* @return
*/
@RequestMapping(method = RequestMethod.POST)
public Result addSpit(@RequestBody Spit spit){
spitService.addSpit(spit);
return new Result(true,StatusCode.OK,"添加成功");
}
/**
*
* 根据id进行查询
* @param spitId
* @return
*/
@RequestMapping(value = "/{spitId}",method = RequestMethod.GET)
public Result selectByIdSpit(@PathVariable String spitId){
return new Result(true,StatusCode.OK,"根据id进行查询",spitService.selectByIdSpit(spitId));
}
/**
* 更新数据成功
* @param spit
* @param spitId
* @return
*/
@RequestMapping(value = "/{spitId}",method = RequestMethod.PUT)
public Result updateSpit(@RequestBody Spit spit,@PathVariable String spitId){
spitService.updateSpit(spit,spitId);
return new Result(true,StatusCode.OK,"更新成功");
}
/**
* 删除
* @param spitId
* @return
*/
@RequestMapping(value = "/{spitId}",method = RequestMethod.DELETE)
public Result deleteByIdSpit(@PathVariable String spitId){
spitService.deleteByIdSpit(spitId);
return new Result(true,StatusCode.OK,"删除成功");
}
/**
* 分页查询
* @param
* @param page
* @param size
* @return
*/
@RequestMapping(value = "/comment/{parentid}/{page}/{size}",method = RequestMethod.GET)
public Result selectByIdParentIdSpit(@PathVariable String parentid,@PathVariable Integer page,@PathVariable Integer size){
return new Result(true,StatusCode.OK,"分页查询成功",spitService.selectByParentIdSpit(parentid,page,size));
}
/**
* 控制不能重复点赞
* @param spitId
* @return
*/
@RequestMapping(value = "/thumbup/{spitId}",method = RequestMethod.PUT)
public Result updateThumbupBySpitId(@PathVariable String spitId){
String userid="10045";
if (redisTemplate.opsForValue().get("thumbup_"+userid+spitId)!=null){
return new Result(true,StatusCode.OK,"取消成功");
}else if (redisTemplate.opsForValue().get("thumbup_"+userid+spitId)==null){
spitService.updateThumbupBySpitId(spitId);
redisTemplate.opsForValue().set("thumbup_"+userid+spitId,"1");
return new Result(true,StatusCode.OK,"点赞成功");
}
return null;
}
}
|