SpringBoot 操作 MongoTemplate

增加文档

insert和save插入规则:
不写集合名,默认对象类名作为集合名(如实体类是A  集合名是a)
写集合名,则把数据写到对应集合下

1.void save(Object var1);                // 传入对象,不传集合名
2.void save(Object var1, String var2);   // 传入对象,传集合名
3.void insert(Object var1);              // 传入对象,不传集合名
4.void insert(Object var1, String var2); // 传入对象,传集合名
// 下面三个方法是批量插入的实现方法
5.void insert(Collection<? extends Object> var1, Class<?> var2);
6.void insert(Collection<? extends Object> var1, String var2);
7.void insertAll(Collection<? extends Object> var1);

insert 和 save 的区别:

插入重复数据
  insert: 若新增数据的主键已经存在,则会抛 org.springframework.dao.DuplicateKeyException 异常提示主键重复,不保存当前数据。
  save: 若新增数据的主键已经存在,则会对当前已经存在的数据进行修改操作。

批操作
  insert: 可以一次性插入一整个列表,而不用进行遍历操作,效率相对较高
  save: 需要遍历列表,进行一个个的插入

更新文档

更新操作API: 

// updateFirst  更新符合条件的第一条
// updateMulti  更新多个,符合条件都会更改
//修改第一条符合条件数据
1.WriteResult updateFirst(Query var1, Update var2, Class<?> var3); // 指定类型
2.WriteResult updateFirst(Query var1, Update var2, String var3); // 指定集合名
3.WriteResult updateFirst(Query var1, Update var2, Class<?> var3, String var4); // 详细指定类型和集合名
//批量修改
4.WriteResult updateMulti(Query var1, Update var2, Class<?> var3); // 指定类型
5.WriteResult updateMulti(Query var1, Update var2, String var3); // 指定集合名
6.WriteResult updateMulti(Query var1, Update var2, Class<?> var3, String var4); // 详细指定类型和集合名
//同updateFirst
7.WriteResult upsert(Query var1, Update var2, Class<?> var3);
8.WriteResult upsert(Query var1, Update var2, String var3);
9.WriteResult upsert(Query var1, Update var2, Class<?> var3, String var4);

全部更新:

import com.mongodb.client.result.UpdateResult;
import org.bson.Document;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

String docId = "08f23d0b-76ff-4d62-ac52-4fc68ceeac21";
Query query = new Query(Criteria.where("_id").is(docId));
UserData userData = new UserData();
userData.setDocId(docId);
userData.setName("jack");
Document document = (Document)mongoTemplate.getConverter().convertToMongoType(userData);
Update update = Update.fromDocument(document);
UpdateResult updateResult = mongoTemplate.updateFirst(query, update, UserData.class);
System.out.println(updateResult.getModifiedCount());    // 1

更新部分字段

String docId = "08f23d0b-76ff-4d62-ac52-4fc68ceeac21";
Query query = new Query(Criteria.where("_id").is(docId));
Update update = new Update();
update.set("name", "Tom");
UpdateResult updateResult = mongoTemplate.updateFirst(query, update, UserData.class);
System.out.println(updateResult.getModifiedCount());    // 1

删除文档

删除文档API

1.WriteResult remove(Object var1);
2.WriteResult remove(Object var1, String var2);
3.WriteResult remove(Query var1, Class<?> var2); // 根据条件删除
4.WriteResult remove(Query var1, Class<?> var2, String var3); // 详细指定类型和集合名进行删除
5.WriteResult remove(Query var1, String var2); // 指定集合名进行删除

根据id删除文档

String docId = "08f23d0b-76ff-4d62-ac52-4fc68ceeac20";
Query query = new Query(Criteria.where("_id").is(docId));
DeleteResult deleteResult = mongoTemplate.remove(query, UserData.class);
System.out.println(deleteResult.getDeletedCount());    // 1

查询

根据id查询

String docId = "08f23d0b-76ff-4d62-ac52-4fc68ceeac20";
UserData userData = mongoTemplate.findById(docId, UserData.class);

查询对象

Query query = new Query();
query.addCriteria(Criteria.where("_id").is("08f23d0b-76ff-4d62"));
mongoTemplate.findOne(query, User.class);

查询列表

List<UserData> userDataList = mongoTemplate.find(query, UserData.class);

筛选查询(带非空判断)

Query query = new Query();
Criteria criteria = new Criteria();
// 不等于查询
if (StringUtils.isNotBlank(id)) {
    criteria = criteria.and("id").ne(id);
}
// 模糊查询
if (StringUtils.isNotBlank(name)) {
    criteria = criteria.and("name").regex(name);
}
query.addCriteria(criteria);
// 执行
List<UserData> list = mongoTemplate.find(q, UserData.class);

筛选查询(更简洁的写法)

Query query = new Query();
// is查询
query.addCriteria(Criteria.where("数据库表字段名").is("你的参数"));
// in查询
query.addCriteria(Criteria.where("数据库字段").in("list"));
// 执行
mongoTemplate.find(query, Class.class,"数据库表名");

要查询同一个字段多个约束需要用andOperator(时间范围查询)

Query query = new Query();
Criteria criteria = new Criteria();
criteria.andOperator(
    Criteria.where("appointmentTime").gte(condition.getStartTime()),
    Criteria.where("appointmentTime").lte(condition.getEndTime())
);
query.addCriteria(criteria);

 分页和排序查询

// select * from user where age > 18 order by age desc limit 1 offset 0

Criteria c = new Criteria();
Query query = new Query(Criteria.where("age").gt(18));
// 添加条件
query.addCriteria(c);
// 排序
query.with(Sort.by(Sort.Direction.DESC, "age"),Sort.Direction.ASC, "createTime"));
// 分页
query.skip(0).limit(3);
// 执行查询
List<UserData> list = mongoTemplate.find(q, UserData.class);

查询数量

long count = mongoTemplate.count(query, UserData.class);

判断是否存在

String docId = "08f23d0b-76ff-4d62-ac52-4fc68ceeac20";
Query query = new Query(Criteria.where("_id").is(docId));
boolean f = mongoTemplate.exists(query,UserData.class);

and查询 

// 创建条件
Criteria criteria = new Criteria();
// 启用and运算符,其中条件都满足即为选中
criteria.andOperator(
    Criteria.where("isConsent").is(MeetingEnum.IS_CONSENT.getCode()),
    Criteria.where("isMeet").is(MeetingEnum.UN_MEET.getCode()),
    Criteria.where("meetTime").gte(sevenDaysAgo)
);
Query query = new Query(criteria);
List<Meeting> meetings = mongoTemplate.find(query, Meeting.class);

or查询

// 创建条件
Criteria criteria = new Criteria();
// 启用or运算符,之中只要一条满足就为true则命中
criteria.orOperator(
    Criteria.where("sendUserId").is(userId)
        .orOperator(
            Criteria.where("senderConfirm").is(MeetingEnum.UN_MEET.getCode()),
            Criteria.where("senderConfirm").is(null)
        ),
    Criteria.where("recUserId").is(userId)
        .orOperator(
            Criteria.where("recipientConfirm").is(MeetingEnum.UN_MEET.getCode()),
            Criteria.where("recipientConfirm").is(null)
        )
);
Query query = new Query(criteria);
List<Meeting> meetings = mongoTemplate.find(query, Meeting.class);

指定返回的字段(BasicDBObject)

// 查询条件
Criteria personId = Criteria.where("personId").is(incentivePolicy.getId());
// 要查询的字段
BasicDBObject fieldsObject = new BasicDBObject();
fieldsObject.put("_id", 0);
fieldsObject.put("info.score", 1);
fieldsObject.put("info.checkupTime", 1);
// 不同版本下这一步可能会有报错
Query query=new BasicQuery(personId.getCriteriaObject(),fieldsObject);
List<IncentivePolicy> user = mongoTemplate.find(query, IncentivePolicy.class);

指定返回的字段(Field)

String docId = "08f23d0b-76ff-4d62-ac52-4fc68ceeac20";
Query query = new Query(Criteria.where("id").is(docId));
Field findFields = query.fields();
List<String> fields = Arrays.asList("name","age","address");
fields.forEach(findFields::include);
UserData data = mongoTemplate.findOne(query, UserData.class);

指定字段不返回

query.fields().exclude("field");

数组查询

数组格式:
{
    name:"小明",
    age:13,
    friends:[
        {
            name:"小王",
            age:12
        },
        {
            name:"小李",
            age:18
        }
    ]
}


// 当要查询朋友中姓名为小王时
// Query query = new Query();
// query.addCriteria(Criteria.where("friends.$.name").is("小王"));
// mongoTemplate.find(query, User.class,"数据库表名");


// 同样更新时也是一样,但是注意,更新时查询条件需要添加
// query.addCriteria(Criteria.where("friends").elemMatch(Criteria.where("name").is("小王"));
// Update update = Update.update("friends.$.friends", "小赵");

聚合查询

例子一:

现在有这么一个集合ReservationOrder,表示预约订单表,里面有一个字段是字符串类型的appointmentTime,代表预约时间,还有一个字段是字符串类型的customerIntention字段,它的值为yes和no两种,代表客户意向,我想按照预约时间的月份分组统计查询,返回各分组的总数和各个分组内客户意向为yes的总数以及对应的月份。

// 假设开始日期为"2021-01-01",结束日期为"2021-12-31"
Date start = new SimpleDateFormat("yyyy-MM-dd").parse("2021-01-01");
Date end = new SimpleDateFormat("yyyy-MM-dd").parse("2021-12-31");

Aggregation aggregation = Aggregation.newAggregation(
    // 添加开始时间和结束时间的筛选条件
    Aggregation.match(Criteria.where("appointmentTime").gte(start).lte(end)),
    // 提取预约时间的月份
    Aggregation.project().andExpression("substr($appointmentTime, 0, 10)").as("month")
        // 添加客户意向字段
        .and("customerIntention").as("intention"),
        // 统计每个月份的总数
        Aggregation.group("month").count().as("total")
        // 统计每个月份中customerIntention值为yes的总数
        .sum(ConditionalOperators.when(ComparisonOperators.valueOf("intention").equalToValue("yes")).then(1).otherwise(0)).as("yesTotal"),
    // 按照月份升序排序
    Aggregation.sort(Sort.Direction.ASC, "_id")
);
AggregationResults<Map> results = dmt.aggregate(aggregation, "Product_ReservationOrder", Map.class);
List<Map> mappedResults = results.getMappedResults();

代码解释:

我们首先在项目投影阶段使用"substr"函数提取预约时间的月份,并将customerIntention字段重命名为intention。然后,在分组阶段,我们使用"group"操作按照月份分组,并使用"count"操作统计每个月份的总数。同时,我们还使用"sum"操作通过条件判断来统计每个月份中customerIntention值为yes的总数。最后,我们使用"sort"操作按照月份升序排序。

通过mongoTemplate执行聚合查询后,我们可以得到一个包含各分组信息的List<Document>类型的结果集。每个文档中包含"_id"字段表示月份、"total"字段表示该月份的总数以及"yesTotal"字段表示该月份中customerIntention值为yes的总数。

例子二:

有这么一个集合Product,里面有字段puton,boolean类型,代表上架状态。我想按照开始日期和结束日期分组统计所有数据的总数、puton为true的总数和puton为false的总数。

// 假设开始日期为"2021-01-01",结束日期为"2021-12-31"
Date start = new SimpleDateFormat("yyyy-MM-dd").parse("2021-01-01");
Date end = new SimpleDateFormat("yyyy-MM-dd").parse("2021-12-31");

Aggregation aggregation = Aggregation.newAggregation(
    // 添加时间范围的筛选条件
    Aggregation.match(Criteria.where("date").gte(start).lte(end)),
    // 统计所有数据的总数
    Aggregation.group().count().as("total")
    // 统计puton为true的总数    
    .sum(ConditionalOperators.when(ComparisonOperators.valueOf("puton").equalToValue(true)).then(1).otherwise(0)).as("trueTotal")
    // 统计puton为false的总数
    .sum(ConditionalOperators.when(ComparisonOperators.valueOf("puton").equalToValue(false)).then(1).otherwise(0)).as("falseTotal"),
    Aggregation.project().andExclude("_id")
);
AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, "Product", Map.class);
List<Map> mappedResults = results.getMappedResults();

代码解释:

其中,我们使用"Criteria.where"方法构建了一个包含开始日期和结束日期的筛选条件,并在聚合操作中使用"match"操作将其添加到管道中。

需要注意的是,在这里我们假设开始日期和结束日期都是以字符串形式传入的,并且格式为"yyyy-MM-dd"。如果实际情况中开始日期和结束日期是以其他格式或其他数据类型(如Long型时间戳)传入的,需要相应地修改代码。

例子三:

有这么一个集合Product,里面有字段sumViewTime代表浏览总时长和viewCount代表浏览次数,我想让查询语句按照sumViewTime除以viewCount(平均浏览时长)的结果排序。

Criteria c = makeCriteria(queryProduct);
ProjectionOperation project = project()
    // 需要返回的Product集合里面的其他字段
    .andInclude("id", "name", "industry", "category", "desc", "income", "imageIds")
    .and("sumViewTime").as("sumViewTime")
    .and("viewCount").as("viewCount")
// 如果viewCount为0,直接返回0
.and(ConditionalOperators.when(ComparisonOperators.Eq.valueOf("viewCount").equalToValue(0))
        .then(0)
// 如果viewCount不为0,再进行除法运算
.otherwiseValueOf(ArithmeticOperators.Divide.valueOf("sumViewTime").divideBy("viewCount"))
    ).as("ratio");
// 排序
SortOperation sort = sort(Sort.Direction.DESC, "ratio");
MatchOperation match = Aggregation.match(c);
// 分页
SkipOperation skip = Aggregation.skip((queryProduct.getPage()) * queryProduct.getSize());
LimitOperation limit = Aggregation.limit(queryProduct.getSize());
// 执行查询
Aggregation aggregation = newAggregation(match, project, sort, skip, limit);
// 返回查询结果
AggregationResults<Map> results = dmt.aggregate(aggregation, "Product", Map.class);
List<Map> result = results.getMappedResults();

代码解释:

在上述代码中,我们首先使用 match 和 project 操作来进行筛选和字段投影,并使用 andExpression 来添加一个新的计算字段 ratio,它存储了 sumViewTime 除以 viewCount 的结果。然后,使用 sort 操作按照计算字段 ratio 进行降序排序。

这里为了避免除以0的情况出现,我们使用 ArithmeticOperators.Conditional 来添加条件判断。当 viewCount 不为0时,使用除法表达式计算 sumViewTime 除以 viewCount 的结果作为 ratio 字段。当 viewCount 为0时,可以使用默认值0或其他处理逻辑。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mephisto180502

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值