前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring Data MongoTemplate简介及示例

Spring Data MongoTemplate简介及示例

作者头像
程序你好
发布2022-11-18 15:33:40
3.7K0
发布2022-11-18 15:33:40
举报
文章被收录于专栏:程序你好程序你好

一、背景

最近手头上的项目使用mongoDB存储物联网设备采集上来的实时数据,增删改查与传统关系数据库差别很大,开发过程中也踩了不少坑,记录下来供有需要的朋友参考。

二、概述

MongoTemplate是由org.springframework.data.mongodb.core包提供一个Java类。它提供了一组用于与MongoDB交互的丰富特性,并充当Spring的MongoDB支持的中心类。此外,MongoTemplate是线程安全的,可以跨多个实例调用。MongoTemplate类实现了接口MongoOperations,提供了流畅的API进行Query, Criteria, Update等基本操作,此外,也支持泛型的方法实现。使用起来也非常方便,可直接将MongoTemplate作为类中的属性来使用。

三、基本操作

1、Insert操作

public <T> T insert(T objectToSave, String collectionName)

插入一个新的User对象,collectionName作为可选参数,可以指定mongodb的某个collection插入

Useruser=newUser(); user.setName("Tom"); mongoTemplate.insert(user, "user");

2、Save – Insert

这也是开发中最常用的一种操作行为,“保存或更新”,如果数据库中有此id,则执行更新,如果没有,则执行插入操作。

添加新用户:

Useruser=newUser(); user.setName("Albert"); mongoTemplate.save(user, "user");

修改现有用户数据:

user = mongoTemplate.findOne( Query.query(Criteria.where("name").is("Jack")), User.class); user.setName("Jim"); mongoTemplate.save(user, "user");

在上面的示例,save使用了update的语义,因为我们更新现存用户信息。

3、UpdateFirst

updateFirst更新与查询匹配的第一条记录。

例如:

数据库中有两条同名记录

[ { "_id" : ObjectId("55b5ffa5511fee0e45ed614b"), "name" : "Alex" }, { "_id" : ObjectId("55b5ffa5511fee0e45ed614c"),

"name" : "Alex" } ]

当我们执行updateFirst

Query query = new Query(); query.addCriteria(Criteria.where("name").is("Alex"));

Update update = new Update(); update.set("name", "James"); mongoTemplate.updateFirst(query, update, User.class);

第一条记录将被更新。

4、UpdateMulti

UpdateMulti更新与给定查询匹配的所有数据记录

Query query = new Query(); query.addCriteria(Criteria.where("name").is("Eugen"));

Update update = new Update(); update.set("name", "Victor"); mongoTemplate.updateMulti(query, update, User.class);

执行之后数据库中的现有对象都将被更新。

5、FindAndModify

跟updateMulti类似,但是它能返回修改对象之前的数据。

Query query = new Query(); query.addCriteria(Criteria.where("name").is("Markus"));

Update update = new Update(); update.set("name", "Nick");

User user = mongoTemplate.findAndModify(query, update, User.class);

返回的用户对象具有与数据库中初始状态相同的值。

6、Upsert

如果记录存在,则更新它,否则通过结合查询和更新对象创建一个新记录。

Query query = new Query(); query.addCriteria(Criteria.where("name").is("Markus"));

Update update = new Update(); update.set("name", "Nick"); mongoTemplate.upsert(query, update, User.class);

7、Remove

删除数据

mongoTemplate.remove(user, "user");

8、findAll(className) OR findAll(className, collectionName)

以上两种方法从数据库中获取List格式的数据。这里T是类名。如果类名和集合名都相同,则使用findAll(T.class),否则使用findAll(T.class, " collectionName ")。

List<User> list = mongoTemplate.findAll(User.class);

9、findById(id, entityClass) OR findById(id, entityClass, collectionName)

我们使用此方法从数据库集合中使用PK(ID)获取数据。如果Id存在,则将JSON Document转换为Object,否则返回null(表示没有对象)。

User user= mongoTemplate.findById(1, User.class);

10、findAndRemove(query, entityClassName)

删除实际从查询条件中获取的数据

代码语言:javascript
复制
Query query= new Query();
query.addCriteria(Criteria.where("cost").is(1749.0));
mongoTemplate.findAndRemove(query, Book.class);

findAllAndRemove(query, entityClassName)

批量删除实际从查询条件中获取的数据

代码语言:javascript
复制
Query query= new Query();
代码语言:javascript
复制
query.addCriteria(Criteria.where("cost").gte(1000.0));
mongoTemplate.findAllAndRemove(query, Book.class);
11、总结:

四、数据查询

上面的示例中我们使用Query对象来查询数据

1、常用数据查询

Query对象 1、 创建一个query对象(用来封装所有条件对象),再创建一个criteria对象(用来构建条件) 2 、精准条件:criteria.and(“key”).is(“条件”) 模糊条件:criteria.and(“key”).regex(“条件”) 3、封装条件:query.addCriteria(criteria) 4、大于(创建新的criteria):Criteria gt = Criteria.where(“key”).gt(“条件”) 小于(创建新的criteria):Criteria lt = Criteria.where(“key”).lt(“条件”) 5、Query.addCriteria(new Criteria().andOperator(gt,lt)); 6、一个query中只能有一个andOperator()。其参数也可以是Criteria数组。 7、排序 :query.with(new Sort(Sort.Direction.ASC, "age"). and(new Sort(Sort.Direction.DESC, "date")))

常用查询示例:

代码语言:javascript
复制
if(null == startDate && null == endDate){
    query.addCriteria(Criteria.where("sqid").gte(calendar.getTime()).lte(calendar2.getTime()));
}else if(null != startDate && null != endDate){
    query.addCriteria(Criteria.where("sqid").gte(startDate).lte(endDate));
}else if(null != startDate){
    query.addCriteria(Criteria.where("sqid").gte(startDate.toInstant()));
}else if(null != endDate){
    query.addCriteria(Criteria.where("sqid").lte(endDate.toInstant()));
}

if(!StringUtils.isEmpty(equipmentId)){
    query.addCriteria(Criteria.where("equipmentID").is(equipmentId));
}

使用count查询记录数:

long count = mongoTemplate.count(new Query().with(new Sort(

Sort.Direction.ASC, "username")), User.class);

代码语言:javascript
复制
组合条件查询:
Query query = new Query(Criteria
                .where("username").is(student.getUsername())
                .and("gender").is(student.getGender())
                .and("age").gt(student.getAge()));
        List<Student> students = mongoTemplate.find(query, Student.class);


模糊查询(模糊查询以 ^开始 以$结束 .*相当于Mysql中的%):
String regex = String.format("%s%s%s", "^.*", username, ".*$");
        Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
        Query query = new Query(Criteria.where("username").regex(pattern));
        List<Student> students = mongoTemplate.find(query, Student.class);
2、使用游标MongoCursor查询数据
因为项目中存储的是每秒一条的实时数据,数据量很大,特定的业务需求
会遍历表中的数据。刚开始是先查询总数,然后再根据总数进行分页查询,
如果数据量特别大,查询到后面的页会越来越慢。
我们使用游标来实现在mongoDB海量数据的查询。

MongoCursor<Document> iterator = mongoTemplate.getCollection(equipment.getEquipmentCode()).find(query.getQueryObject()).noCursorTimeout(true).batchSize(BATCH_SIZE).iterator();
 MongoWits58 lastEntity = null;

MongoCursor iterator1 = mongoTemplate.getCollection(equipment.getEquipmentCode()).find(query.getQueryObject()).iterator();while (iterator.hasNext()){
    Document document = (Document)iterator.next();
    //
    if(lastEntity == null){
        ****
    }else {
       ****
        lastEntity = entity;
    }

    //if(taskExist())
}

cursor
cursor的获取:find() 方法返回的是一个 FindIterable 对象,对此对象的控制即可对 cursor 的属性进行控制,根据FindIterable获取一个Cursor 。
1)batchSize(int size):每次网络请求返回的document条数,比如你需要查询500条数据,mongodb不会一次性全部load并返回给client,而是每次返回batchSize条,遍历完之后后再通过网路IO获取直到cursor耗尽。默认情况下,首次批量获取101个document或者1M的数据,此后每次4M,当然我们可以通过此方法来覆盖默认值,如果文档尺寸较小,则建议batchSize可以大一些。
2)skip(int number)、limit(int number):同SQL中的limit字句,即表示在符合匹配规则的结果集中skip一定数量的document,并最终返回limit条数据。可以实现分页查询。
3)maxTime(int time,TimeUnit unit):表示此次操作保持的最长时间,即server端保持cursor状态的最长时间,如果超时server端将移除此cursor,即再次通过此cursor遍历数据将会error。
4)sort(Bson bson):根据指定field排序,参与排序的字段最好是索引,如果不是,将会在内存中排序,如果参与排序的数据尺寸大于32M,将会抛出error。1表示正序,-1表示倒叙,比如"age":1表示按照age正序排序。
5)noCursorTimeout(boolean timeout):如果cursor空闲一定时间后(10分钟),server端是否将其移除,默认为false,即server会将空闲10分钟的cursor移除以节约内存。如果为true,则表示server端不需要移除空闲的cursor,而是等待用户手动关闭。无论如何,开发者都需要注意,手动关闭cursor。
6)partial(boolean partial):对于sharding集群,如果一个或者多个shard不可达,是否允许返回部分数据(只从正常的shard中获取数据)。
7)cursorType():指定cursor类型,当cursor遍历完毕后是否关闭cursor,默认是关闭,无论何时都建议手动关闭cursor(不管是否耗尽curosr);当然有些开发场景可能需要保持cursor的活性,遍历到cursor的最后一条后,不关闭cursor,继续等待,此后一段时间内如果有新数据插入到cursor之后,则可以继续遍历,这就是Tailable Cursor,通常对于Capped Collection中使用。目前支持支持3种类型的Cursor:NonTailable、Tailable、TailableAwait。


五、MongoDB 聚合查询
MongoDB中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果。
管道在Unix和Linux中一般用于将当前命令的输出结果作为下一个命令的参数。
MongoDB的聚合管道将MongoDB文档在一个管道处理完毕后将结果传递给下一个管道处理。管道操作是可以重复的。
表达式:处理输入文档并输出。表达式是无状态的,只能用于计算当前聚合管道的文档,不能处理其它的文档。
聚合管道的每个阶段在文档通过时对文档进行转换。输入文档经过一个阶段后,它不一定会产生一个输出文档。有些阶段可能生成多个文档作为输出。
$project
对输入中的记录进行再次投影,按照我们需要的格式生成结果集。例如,通过添加新字段或删除现有字段。对于每个输入数据,只有一个输出。
$match
按匹配过滤记录,只允许匹配的记录未经修改地传递到下一个管道阶段。对于每个输入,输出要么是一个记录(匹配),要么是0个(不匹配)。
$group
按指定的标识符表达式对输入文档进行分组,并对每个组应用累加器表达式(如果指定了)。$group使用所有输入文档,并为每个不同的组输出一个文档。输出文档只包含标识符字段(组id),如果指定,则包含累计字段。
  • $sort

按指定的排序对文档流重新排序。一个输入一个输出。

  • $skip 跳过前n个文档(其中n是指定的跳过号),并将剩余的文档未经修改地传递给管道。对于每个输入文档,输出要么是零文档(对于前n个文档),要么是一个文档(在前n个文档之后)
  • $limit

将前n个未修改的文档传递到n为指定限制的管道。对于每个输入文档,输出要么是一个文档(对于前n个文档),要么是0个文档(在前n个文档之后).

  • $unwind

将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值

下表展示了一些聚合的表达式:

示例: operations.add(Aggregation.match(Criteria.where("course").is(studentScore.getCourse())));     operations.add(Aggregation.group("course").sum("score").as("totleScore"));   }   Aggregation aggregation = Aggregation.newAggregation(operations);   //查询、并获取结果   AggregationResults<StudentScore> results = mongoTemplate.aggregate( aggregation, "studentScore", StudentScore.class);   double totleScore = results.getUniqueMappedResult().getTotleScore(); 5、总结 本文记录个人学习使用MongoTemplate操作MongoDB一些基本的语句,使用过程中还发现需要注意的一些问题: mongodb返回数据过大,查询报错,一次性查出N条数据并进行 sort 排序,然后在使用Java代码查询时候, 直接抛出了异常 。 建立索引时间过长,MongoDB 提供了两种建索引的访问,一种是 background 方式,不需要长时间占用写锁,另一种是非 background 方式,需要长时间占用锁。使用 background 方式就可以解决问题。 日期格式问题 mongodb的日期时间格式是UTC时间,中国时间 = UTC时间 +8

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-09-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序你好 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、背景
  • 二、概述
  • 3、UpdateFirst
  • 4、UpdateMulti
  • 5、FindAndModify
  • 10、findAndRemove(query, entityClassName)
  • findAllAndRemove(query, entityClassName)
相关产品与服务
云数据库 MongoDB
腾讯云数据库 MongoDB(TencentDB for MongoDB)是腾讯云基于全球广受欢迎的 MongoDB 打造的高性能 NoSQL 数据库,100%完全兼容 MongoDB 协议,支持跨文档事务,提供稳定丰富的监控管理,弹性可扩展、自动容灾,适用于文档型数据库场景,您无需自建灾备体系及控制管理系统。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档