MongoDB
点赞,评论这块可能操作起来比较频繁,并且,这两块的内容不怎么重要,因此可以使用MongoDB
什么是MongoDB
MongoDB 是一个跨平台的,面向文档的数据库(solr、Elasticsearch),是当前 NoSQL 数据库产品中最热门的一种。它介于关系数据库和非关系数据库之间,是非关系数据库当中功能最丰富,最像关系数据库的产品。它支持的数据结构非常松散,是类似 JSON 的 BSON 格式,因此可以存储比较复杂的数据类型。比如表中表
MongoDB特点
MongoDB 最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。它是一个面向集合的,模式自由的文档型数据库。具体特点总结如下:
(1)面向集合存储,易于存储对象类型的数据
(2)模式自由
(3)支持动态查询
(4)支持完全索引,包含内部对象
(5)支持复制和故障恢复
(6)使用高效的二进制数据存储,包括大型对象(如视频等)
(7)自动处理碎片,以支持云计算层次的扩展性
(8)支持 Python,PHP,Ruby,Java,C,C#,Javascript,Perl 及 C++语言的驱动程序,社区中也提供了对 Erlang 及.NET 等平台的驱动程序
(9) 文件存储格式为 BSON(一种 JSON 的扩展)
MongoDB体系结构
MongoDB 的逻辑结构是一种层次结构。主要由:文档(document)、集合(collection)、数据库(database)这三部分组成的。逻辑结构是面向用户的,用户使用 MongoDB 开发应用程序使用的就是逻辑结构。
(1)MongoDB 的文档(document),相当于关系数据库中的一行记录。
(2)多个文档组成一个集合(collection),相当于关系数据库的表。
(3)多个集合(collection),逻辑上组织在一起,就是数据库(database)。
(4)一个 MongoDB 实例支持多个数据库(database)
数据类型
基本数据类型
null:用于表示空值或者不存在的字段,{“x”:null}
布尔型:布尔类型有两个值true和false,{“x”:true}
数值:mongo默认使用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字节的字符串,是文档的唯一标识,{“_id”: objectId() }
二进制数据:二进制数据是一个任意字节的字符串。它不能直接在shell中使用。如果要将非utf-字符保存到数据库中,二进制数据是唯一的方式。
代码:查询和文档中可以包括任何JavaScript代码,{“x”:function(){/…/}}
Docker安装MongoDB
docker pull mongo
docker run -di --name=mongo -p 27017:27017 mongo
常用命令
选择和创建数据库
选择和创建数据库的语法格式:
use 数据库名称
如果数据库不存在则自动创建
插入与查询文档
插入文档的语法格式:
db.集合名称.insert({BSON格式的数据})
查询集合的语法格式:
db.集合名称.find()
查询用户id是233的数据
db.集合名称.find({userId: ‘233’})
只查询一条
db.集合名称.findOne({userId: ‘233’})
返回指定条数的记录
db.集合名称.find().limit(3)
修改与删除文档
修改文档的语法结构:
Db.集合名称.update(条件,修改后的数据)
如果我们想修改_id为1的记录,名称为张三,输入以下语句:
Db.集合名称.update({_Id:ObjectId(1)}, {name:’张三’})
执行后,我们会发现,这条文档除了name字段其它字段都不见了,为了解决这个问题,
我们需要使用修改器$set来实现,命令如下:
Db.集合名称.update({{_Id:ObjectId(1)}:1}, {$set:{name:’张三’}})
删除文档的语法结构:
Db.集合名称.remove(条件)
以下语句可以将数据全部删除,请慎用
Db.集合名称.remove({})
统计条数
统计记录条件使用count()方法
Db.集合名称.count()
Db.集合名称.count(条件)
模糊查询
MongoDB的模糊查询是通过正则表达式的方式实现的。格式为:
/字符串/
比如标题中包含java的帖子
Db.集合名称.find(title:/java/)
比如查询以“张”开头的名字
Db.集合名称.find(name: /^张/)
大于 小于 不等于 包含 不包含
大于: g t , 小 于 gt,小于 gt,小于lt,大于等于 g t e , 小 于 等 于 gte,小于等于 gte,小于等于lte,不等于 n e , 包 含 ne,包含 ne,包含in,不包含$nin
查询阅读数大于10的帖子
Db.集合名称.find({readNum:{$gt:10}})
查询评论集合中userid字段不包含1013和1014的文档
Db.集合名称.find({userId: {$nin:[‘1013’, ‘1014’]}})
条件连接
我们如果需要查询同时满足两个以上条件,需要使用$and操作符将条件进行关联。(相
当于SQL的and)
格式为:
$and:[ { },{ },{ } ]
示例:查询帖子集合中readNum大于等于1000 并且小于2000的文档
Db.集合名称.find( {KaTeX parse error: Expected '}', got 'EOF' at end of input: …d: [ {readNum:{gte:1000}}, {readNum:{$lte: 2000}} ]} )
如果两个以上条件之间是或者的关系,我们使用$or 用法和and相同
$or:[ { },{ },{ } ]
列值增长
如果我们想实现对某列值在原有值的基础上进行增加或减少,可以使用$inc运算符来实现
Db.集合名称.update({_Id:ObjectId(1)}, {$inc:{readNum:NumberInt(2)}})
在springboot项目中使用
依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
yml配置
spring:
data:
mongodb:
host: 121.89.192.157
database: blog
port: 27017
dao接口
@Repository
public interface CommentDao extends MongoRepository<Comment, String> {
/**
* 根据博客id查询
* 根据时间降序排序
* @param commentBlog
* @return
*/
List<Comment> getCommentsByCommentBlogOrderByCreatedTimeDesc(String commentBlog);
}
JPA语法
Keyword | Sample | JPQL snippet |
---|---|---|
And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 |
Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
Is,Equals | findByFirstname ,findByFirstnameIs ,findByFirstnameEquals | … where x.firstname = ?1 |
Between | findByStartDateBetween | … where x.startDate between ?1 and ?2 |
LessThan | findByAgeLessThan | … where x.age < ?1 |
LessThanEqual | findByAgeLessThanEqual | … where x.age ⇐ ?1 |
GreaterThan | findByAgeGreaterThan | … where x.age > ?1 |
GreaterThanEqual | findByAgeGreaterThanEqual | … where x.age >= ?1 |
After | findByStartDateAfter | … where x.startDate > ?1 |
Before | findByStartDateBefore | … where x.startDate < ?1 |
IsNull | findByAgeIsNull | … where x.age is null |
IsNotNull,NotNull | findByAge(Is)NotNull | … where x.age not null |
Like | findByFirstnameLike | … where x.firstname like ?1 |
NotLike | findByFirstnameNotLike | … where x.firstname not like ?1 |
StartingWith | findByFirstnameStartingWith | … where x.firstname like ?1 (parameter bound with appended % ) |
EndingWith | findByFirstnameEndingWith | … where x.firstname like ?1 (parameter bound with prepended % ) |
Containing | findByFirstnameContaining | … where x.firstname like ?1 (parameter bound wrapped in% ) |
OrderBy | findByAgeOrderByLastnameDesc | … where x.age = ?1 order by x.lastname desc |
Not | findByLastnameNot | … where x.lastname <> ?1 |
In | findByAgeIn(Collection<Age> ages) | … where x.age in ?1 |
NotIn | findByAgeNotIn(Collection<Age> age) | … where x.age not in ?1 |
True | findByActiveTrue() | … where x.active = true |
False | findByActiveFalse() | … where x.active = false |
IgnoreCase | findByFirstnameIgnoreCase | … where UPPER(x.firstame) = UPPER(?1) |
分页查询
@Test
void testByPage() {
//构造分页查询条件
Comment comment = new Comment();
comment.setCommentUser(1);
Example<Comment> example = Example.of(comment);
Pageable pageable = PageRequest.of(1, 5);
//执行查询
org.springframework.data.domain.Page<Comment> page1 = this.commentDao.findAll(example, pageable);
//封装返回数据
List<Comment> content = page1.getContent();
content.forEach(System.out::println);
}
Query
查询方法定义的两种方式
- 根据方法名来自动推测
- 自定义
本文介绍自定义的方式
@Query注解
Mongodb使用的是基于json的查询语句。
通过将org.springframework.data.mongodb.repository.Query批注添加到存储库查询方法,可以指定要使用的MongoDB JSON查询字符串,而不是从方法名称派生查询,如以下示例所示:
public interface PersonRepository extends MongoRepository<Person, String>
@Query("{ 'firstname' : ?0 }")
List<Person> findByThePersonsFirstname(String firstname);
}
占位符 ?0 是函数的参数。
注意: String类型的参数在绑定过程中会进行转义, 这意味着不能为之添加特殊的参数。
可以使用fields来设置返回的字段:
@Query(value="{ 'firstname' : ?0 }", fields="{ 'firstname' : 1, 'lastname' : 1}")
List<Person> findByThePersonsFirstname(String firstname);
上例中结果Person对象中只会有firstname、lastname 和id 属性 , 其他属性没有 。
在基于json的查询中使用SpEL表达式
查询串和field返回定义可以使用SpEL表达式 在运行时进行动态创建 。
表达式通过包含所有参数的数组公开方法参数。 以下查询使用[0]声明lastname的谓词值(相当于?0参数绑定):
public interface PersonRepository extends MongoRepository<Person, String>
@Query("{'lastname': ?#{[0]} }")
List<Person> findByQueryWithExpression(String param0);
}
当传入参数为对象时, 实例:
@Query(value="{'name': ?#{ [0].name }}")
public Page<RcControllJournalDo> querylikepages(RcControllJournalDo mdo, Pageable pageable);
上例等价于 where name = mdo.name .
更复杂的实例:
/**
* 当mdo.name为空时, 查询条件为 { "name" : { "$exists" : true } } ,即查询所有name列存在的记录(包括值为null的记录,但是对于没有name列的查询不到) ;
* 当mdo.name不空时,查询条件为 { "name" : [0].name }
*/
@Query(value=" { 'name': ?#{ ([0].name == null) or ([0].name.length() == 0) ? '{$exists:true}' : [0].name } } ")
public Page<RcControllJournalDo> querylikepages2(RcControllJournalDo mdo, Pageable pageable);
#{ ([0].name == null) or ([0].name.length() == 0) ? '{$exists:true}' : [0].name }
为SpEL表达式 (三目表达式)。
模糊查询例子:
/**
* 使用正则表达式模糊查询
*/
@Query(value=" { 'idno': ?#{ ([0].name == null) or ([0].name.length() == 0) ? {$exists:true} : {$regex: [0].name } } } ")
public Page<RcControllJournalDo> querylikepages21(RcControllJournalDo mdo, Pageable pageable);
mongodb的正则表达式查询语法为:
>db.posts.find({post_text:{$regex:"runoob"}})
>db.posts.find({post_text:{$regex:"runoob",$options:"$i"}})
例子:
根据前端上送的查询条件模糊匹配name 和idno , 当有值时查询之,无则查询所有:
/**
* 模糊查询name 和 idno <br>
* 1. mongodb or语法 :{ $or :[{}, {},...] } 例子: {$or:[{"by":"aaa"} , {"title": "bbb"}]} , 即 where by=aaa or title=bbb <BR>
* 2. { $or :[{'name' : ?#{}}, {'idno' : ?#{}}] } <br>
*
*/
@Query(value=" { $or :[{'name' : ?#{ ([0].name == null) or ([0].name.length() == 0) ? '{$exists:true}' : {$regex:[0].name} }},"
+ " {'idno' : ?#{ ([0].idno == null) or ([0].idno.length() == 0) ? '{$exists:true}' : {$regex: [0].idno} }}] } ")
public Page<RcControllJournalDo> querylikepages3(RcControllJournalDo mdo, Pageable pageable);
输入参数:
mdo.setName(“宋”);
mdo.setIdno(“112”);
打印的日志为:
find using query: { "$or" : [{ "name" : { "$regex" : "宋" } }, { "idno" : { "$regex" : "112" } }] }