增加文档
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或其他处理逻辑。