MongoDB数据库查询,和SpringBoot整合使用 ,@query的用法

前序说明:(随时补充更新

关于Mongo数据库的网上资料又乱又少,所以针对用过的进行一个循序渐进的总结;

  1. 关于Mongo(如果觉得关于不想看,直接跳到使用阶段 2)
  2. Mongo的使用:
    (1) 数据库中常用的查询 shell 写法实现总结;
    (2)SpringBoot和Mongo整合的一些使用优势:
    (3)mongoDB中 service层实现query方式拼接sql;
    (4)在DAO层,使用@query注解实现 sql的方式;
    EG:特殊的一些操作:查询一个Collection ,指定返回的字段;
一、关于MongoDB
1. MongoDB是什么?

MongoDB(是一款C++编写的非常热门的Nosql,面向完蛋的数据库管理系统)是一个基于分布式文件存储的数据库,是一个介于关系数据库和非关系数据库当中功能最丰富,最像关系数据库的。他支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。

2. 为什么要使用MongoDB? 有哪些优势和不足?不适用的场景?

优势:
(1)查询非常快:由于MongoDB独特的数据处理方式,可以将热点数据加载到内存,故而对查询来讲,会非常快(当然也会非常消耗内存),MongoDB数据存在内存,由linux系统mmap实现,当内存不够时,只将热点数据放入内存,其他数据存在磁盘;所以在这里,重要的是要有正确的索引和足够强大的RAM来从MongoDB中获益;
(2)Bson的数据结构,很好操作和处理:(可以存储多个类型的值到数据库中)同时由于采用了BSON的方式存储数据,故而对JSON格式数据具有非常好的支持性以及友好的表结构修改性,文档式的存储方式,数据友好可见;
(3)数据库的分片集群负载具有非常好的扩展性以及非常不错的自动故障转移(大赞)。(内置Auto-Sharding自动分片支持云级扩展性,分片简单)
(4)内置GridFS,支持大容量存储;GridFS是一个出色的分布式文件系统,可以支持海量的数据存储。内置了GridFS 的MongoDB,能够满足大数据集的快速范围查询。如果在平时的开发过程中,有数据集非常大的情况,可以使用它来进行处理;
(5)全索引支持: 它的索引能够扩展到内部对象和内嵌的数组,也就是说,如果一个对象有一个内嵌对象,MongoDB可以针对内嵌对象中的字段进行索引的添加;
(6)MongoDB支持复杂的聚合,(下面会有一个栗子,当时写一个超级复杂的聚合方法,写了俩小时…)(个人觉得,如果了解透了那些词的作用,写出一个聚合会很不错的。)

不足:
(1)数据库的查询采用了特有的查询方式,有一定的学习成本(不高);
(2)锁只能提供到collection级别,还做不到行级锁;
(3)没有事务机制(不能回滚啊); (这里被好心的网友提醒了,刚才去查新鲜资料的时候,还是有很多的文章总结说依旧不支持事务。其实单独针对事务去搜索看看的时候,就知道 —MongoDB 4.0 引入的事务功能。 敲重点:看官方文档很重要。 关于MongoDB事务的点 这里就先不展开讲了。待研究一下 )(刚看了三个比较正规的教程网址,第一句上来就说 不支持事务,我的膝盖。。)
所以这里还是附上官网地址: MongoDB官网
MongoDB的事务
【For situations that require atomicity of reads and writes to multiple documents (in a single or multiple collections), MongoDB supports multi-document transactions. With distributed transactions, transactions can be used across multiple operations, collections, databases, documents, and shards.】同时在使用事务的时候,可以自定义读首选项,以及读写权限的范围;
(4)学习资料肯定没有MySQL的多。

不适用的场景:
需要使用复杂sql的查询;(这里的复杂不是指需要高度聚合的那种,而是表与表之间进行的复杂查询);

3. Nosql数据库的理论基础 和MongoDB相关

(1) CAP理论: 分别代表 Consistency(强一致性),Availability(可用性),Partition Tolerance(分区容错);
C:系统在执行某项操作后仍然处于一致的状态。在分布式系统中,更新操作执行成功之后,所有的用户都能读取到最新的值,这样的系统被认为具有强一致性。
A:用户执行的操作在一定时间内,必须返回结果。如果超时,那么操作回滚,跟操作没有发生一样。
P:分布式系统是由多个分区节点组成的,每个分区节点都是一个独立的Server,P属性表明系统能够处理分区节点的动态加入和离开。

(2) 在构建分布式系统的时候,必须考虑CAP特性。
①传统的关系型DB,注重的是CA特性(分区容错性),数据一般存储在一个server上。
②而处理海量数据的分布式存储和处理系统高更注重AP(强一致性),Nosql保留数据的最终一致性。

4. MongoDB支持的数据类型:

(1) 字符串 - 这是用于存储数据的最常用的数据类型。MongoDB中的字符串必须为UTF-8。
(2) 整型 - 此类型用于存储数值。 整数可以是32位或64位,具体取决于服务器。
(3) 布尔类型 - 此类型用于存储布尔值(true / false)值。
(4) 双精度浮点数 - 此类型用于存储浮点值。
(5) 最小/最大键 - 此类型用于将值与最小和最大BSON元素进行比较。
(6) 数组 - 此类型用于将数组或列表或多个值存储到一个键中。
(7) 时间戳 - ctimestamp,当文档被修改或添加时,可以方便地进行录制。
(8) 对象 - 此数据类型用于嵌入式文档。
(9) Null - 此类型用于存储Null值。
(10) 符号 - 该数据类型与字符串相同; 但是,通常保留用于使用特定符号类型的语言。
(11) 日期 - 此数据类型用于以UNIX时间格式存储当前日期或时间。您可以通过创建日期对象并将日,月,年的日期进行指定自己需要的日期时间。
(12) 对象ID - 此数据类型用于存储文档的ID。
(13) 二进制数据 - 此数据类型用于存储二进制数据。
(14) 代码 - 此数据类型用于将JavaScript代码存储到文档中。
(15) 正则表达式 - 此数据类型用于存储正则表达式。

5. 学习链接:

简书教程(包括常用的一些命令)
简书 可视化工具和一些命令
可视化工具使用教程

二、 数据库中常用的查询 shell 写法实现总结

1. 在navicat中操作实现查询sql;

这个就比较简单了,有一个非常简单的方法:
就是在navicat软件中选择具体的某个collection 构建查询语句,点击确定,即可自动生成查询语句;
@query中的条件,也可以使用这种方式,生成query语句,放在@query的value中;

2. 常用的一些查询:

关键词:
$gt大于
$lt小于
$ne不等于
$gte大于或等于
$lte小于或等于
$inc可以对文档的某个值为数字型(只能为满足要求的数字)的键进行增减的操作。
$in相当于T-SQL中的in
$nin相当于T-SQL中的not in
$set用来指定一个键并更新键值,若键不存在并创建。
KaTeX parse error: Expected '}', got 'EOF' at end of input: … "20120002"},{"inc":{“size” : 1}})
$set用来指定一个键并更新键值,若键不存在并创建。

  • db.a.update({“uid” : “20120002”},{"$set":{“size”:10}})

$unset主要是用来删除键。

  • db.a.update({“uid” : “20120002”},{"$unset":{“sname”:“abc”}})

$push向数组添加新的值。如果键值不存在,则创建一个。

  • db.c.update({“name” : “toyota”},{$push:{“title”:“t1”}})

$addToSet主要给数组类型键值添加一个元素时,避免在数组中产生重复数据。

  • db.c.update({“name” : “toyota”},{$addToSet:{“title”:“t2”}})

$pop从数组的头或者尾删除数组中的元素

  • db.c.update({“name” : “toyota”},{$pop:{“title”:1}})

$pull从数组中删除满足条件的元素

  • db.c.update({“name” : “toyota”},{$pull:{“title”:“t2”}})

三、 SpringBoot和Mongo整合的一些使用优势:

1. DAO继承MongoRepository

这个MongoRepository是mongo提供的一个封装好的基类,相当于SpringDataJpa的思想,(重点:尽管里面没有定义任何一个方法,想要使用封装好的,就需要继承;)
(1)可以通过 方法名称直接生成对应的sql;
和JPA的思想差不多:
比如:根据用户名称查找 对应的用户信息:findByUserName(String userName);

一些常用的:
· {countBy的使用} – 根据userName查询所有符合条件的count: countByUserName();
· {In的使用 } – 根据用户年级查询符合在list参数中的条目:findByGradeIn(List gradeList);
· {Contains和Between的使用} – 查询方法列表包含参数1以及完成时间在参数2.3之间的所有条目:findByMethodListContainsAndFinishTimeBetween()

(2)使用@Query进行查询条件的拼接:

  • 小窍门
	@Query("{ userName: ?0, is_delete : false }")
    List findByUserName(StringuserName);

这里有个小窍门:Query中的条件查询语句的构建
可以使用navicat进行构建, 构建完成之后,直接放进来就成;
MongoDB数据库查询,和SpringBoot整合使用 ,@query的用法_第1张图片

  • @Query 介绍一下Query吧:
    value={} 表示条件;
    filed={} 表示返回哪几个字段;

举个例子
查询一个Collection ,指定返回的字段;
【使用Query中的filed属性来定义,1表示显示,0表示不显示;】

//只输出id和title字段,第一个参数为查询条件,空代表查询所有
db.news.find( {}, { id: 1, title: 1 } )
//如果需要输出的字段比较多,不想要某个字段,可以用排除字段的方法
//不输出内容字段,其它字段都输出。
db.news.find( {}, {content: 0 } )

第一种实现 Criteria和query一起:
在这里插入图片描述
第二种实现:使用@quer{value="{}",field="{}"}的形式:

	@Query(value = "{is_disposed : false, status : { $nin : [0,2] }}", fields = "{request_id: 1,_id: 0}")
    List<LogHwPush> findByStatusAndIsDisposed();

经验之谈,这里有个坑:
在value和field参数值中引号里面都要有一个大括号
否则会报一个异常:org.bson.BsonInvalidOperationException: readStartDocument can only be called when CurrentBSONType is DOCUMENT, not when CurrentBSONType is STRING.
这个异常的大概意思是说:就是你查询出来对应的结果 对应的也应该是一个大括号包含的 bson 格式的 document 而没有大括号的话 就是对应的结果是String。 String是不能自己转成bson格式的;
但是我当时硬是没明白,使用了另一种方法解决:就是重新定义一个类,只接受filed中指定的参数,这样是可以的,就是使用了java基础,显得有点笨;
就说 mongodb不可能这么不完美!!!

  • 如果又想使用@query条件拼接,又想分页;
    则可是这样实现:
    Page getUserByUserName(PageAble pageable);
    ---- PageAble pageable = PageRequest.of(PageNumber number,PageSize size,Sort sort);

(3)也可以直接在service层,使用Repository直接调用 其中提供的好很多现成封装好的 CRUD 以及 分页 排序的方法;非常方便;

四、 mongoDB中 service层实现query方式拼接sql

1. 可以使用Criteria和query一起,进行sql的拼装:

for Eg:分页 条件查询,并且根据某个字段进行排序:

	//使用MongoTemplate 
	@Autowired
    private MongoTemplate mongoTemplate;
 	@Override
    public List<User> getLogByMessageIdAndMethod() {
        List<Criteria> criteriaList = new ArrayList<>();
        criteriaList.add(Criteria.where("name").is("zhangsan"));
        criteriaList.add(Criteria.where("age").is("2"));
        Query query = new Query(new Criteria().andOperator(criteriaList.toArray(new Criteria[]{})));
        Sort sort = new Sort(Sort.Direction.DESC, "createTime");
        PageAble page = PageRequest.of(0,100,sort);
        return mongoTemplate.find(query.with(page), User.class);
    }
2. 在service中通过Criteria 构建 update user set userName =“zhangsan” where user_id = “1234567890”;
Criteria criteria = new Criteria() {
            @Override
            public Document getCriteriaObject() {
                Document criteriaObject = new Document();
                criteriaObject.put("status", User.Status.READY);
                criteriaObject.put("$where", "this.a= this.b");
                return criteriaObject;
            }
        };
        Update update = new Update().set("status", User.Status.FINISHED)
                .set("update_time", new Date());
        UpdateResult result = mongoOperations.updateMulti(new Query(criteria), update, User.class);

六、 现实使用中 特殊 的一些操作:

1. mongo的聚合查询 SpringData mongo:

todo:根据name进行聚合 分组查询年龄总和、第一个年龄、和将年龄放入一个set集合中返回
插入数据:

		mongoTemplate.save(new Role("zhang1",5));
        mongoTemplate.save(new Role("zhang2",6));
        mongoTemplate.save(new Role("zhang3",12));
        mongoTemplate.save(new Role("zhang4",14));
        mongoTemplate.save(new Role("zhang5",23));
        mongoTemplate.save(new Role("zhang1",6));
        mongoTemplate.save(new Role("zhang5",24));

查询:

		 TypedAggregation<Role> agg = Aggregation.newAggregation(Role.class,
                Aggregation.group("name").
                        sum("age").as("agesum").
                        first("age").as("agefirst").
                        addToSet("age").as("agess")
                );
        AggregationResults<Document> result = mongoTemplate.aggregate(agg,Document.class);
        result.getMappedResults().forEach(document -> System.out.println(document));
        

结果:

Document{{_id=zhang1, agesum=11, agefirst=5, agess=[6, 5]}}
Document{{_id=zhang2, agesum=6, agefirst=6, agess=[6]}}
Document{{_id=zhang3, agesum=12, agefirst=12, agess=[12]}}
Document{{_id=zhang5, agesum=47, agefirst=23, agess=[24, 23]}}
Document{{_id=zhang4, agesum=14, agefirst=14, agess=[14]}}

太棒的一个网址总结SpringData结合mongo的使用:https://juejin.im/post/5afb9de8518825426c690307

总结:

  1. Aggregation:看其源码可知,其中有很多的操作,
    比如:sort(),group(), sortByCount(),skip(),limit(),simple(),match(Criteria criteria)匹配某个Criteria条件,
  2. group的一些特性:
    count(),sum(),addToSet(),last(),first(),avg(),push(),min(),max().

你可能感兴趣的:(数据库-持久层-相关,数据库相关)