场景:一个设备的molde属性,该属性定义在物模型中,且使用属性通过上报的方式存在设备数据ThingData中,每次都会存一条并记录时间;通过点击传thingId,再通过id调用dubbo访问其他服务根据thingId获取到对应的productId,且productId关联物模型的id,以此拿到物模型定义中的property数组,其中每个property都有一个唯一标识,而属性上报也是根据唯一值来做判断对应的属性的;通过循环property列表拿到标识让后再ThingData文档中先筛选出符合的数据,然后还要根据场景来判断是否需要进行模糊匹配得到所有符合idenfier或value的存在thingData中的最新值;
!!!注意细节:mongo的映射关系,还有文档名必须正确还要注意层级关系!
需求1.多条件查询的难点:的双属性模糊匹配
listThingPropertiesData(String thingId, String keyWords, Integer pageSize, Integer pageNum) {
ThingModelDTO thingModelData = getThingModelByThingId(thingId);
// 遍历设备物模型的所有属性,每个属性读取最新值
List
// 创建一个空的关键字条件
Criteria keywordCriteria = new Criteria();
// 如果有关键字,添加模糊匹配规则
if (StringUtils.hasText(keyWords)) {
keywordCriteria = keywordCriteria.orOperator(
Criteria.where("property.identifier").regex(keyWords, "i"), // 匹配标识符
Criteria.where("property.value").regex(keyWords, "i") // 匹配属性值
);
}
for (ThingModelDTO.PropertyDTO propSpecDTO : propertiesSpec) {
String propIdentifier = propSpecDTO.getIdentifier();
// 第一步:构建基本查询条件,根据thingId和属性标识符查询
Criteria baseCriteria = Criteria.where("thingId").is(thingId)
.and("property.identifier").is(propIdentifier);
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.match(baseCriteria),
// 如果有关键字,再执行模糊匹配
Aggregation.match(keywordCriteria),
Aggregation.sort(Sort.by(Sort.Order.desc("property.timestamp"))),
Aggregation.group("property.identifier")
.first("property.identifier").as("identifier")
.first("property.value").as("value")
.first("property.timestamp").as("timestamp")
);
try {
AggregationResults
aggregation,"thingData", ThingData.PropertyData.class);
List
propertiesData.addAll(matchingData);
// 添加ThingModel中有但ThingData中没有的属性
if (matchingData.isEmpty()) {
propertiesData.add(new ThingData.PropertyData("ThingModel:" + propSpecDTO.getIdentifier(), null, System.currentTimeMillis()));
}
}catch (Exception e) {
log.debug("查询失败! 原因" + e);
throw new ServiceException(ServiceException.ExceptionType.INTERNAL_FAILURE,
ExceptionInfoBuilder.build(ExceptionTemplate.INTERNAL_FAILURE_DATABASE,"聚合查询"));
}
}
List
int startIndex = (pageNum - 1) * pageSize;
int endIndex = Math.min(startIndex + pageSize, propertyDataDTOs.size());
List
.skip(startIndex)
.limit(endIndex - startIndex)
.collect(Collectors.toList());
return ResponseDTOBuilder.build(paginatedList, propertyDataDTOs.size(), pageSize, pageNum);
}
需求2.:多条件查询难点:筛选只符合一个时间段内的最新数据;
listThingServicesData(String thingId, String status, Long startTime, Long endTime, Integer pageSize, Integer pageNum) throws ServiceException {
// 遍历设备物模型的所有服务,每个服务读取最新值
List
for (ThingModelDTO.ServiceDTO serviceSpecDTO : servicesSpec) {
String serviceIdentifier = serviceSpecDTO.getIdentifier();
// 构建基本查询条件,根据thingId和服务标识符查询
Criteria baseCriteria = Criteria.where("thingId").is(thingId)
.and("service.identifier").is(serviceIdentifier);
// 创建一个空的关键字条件
Criteria keywordCriteria = new Criteria();
if (status != null && !status.isEmpty()) {
keywordCriteria = keywordCriteria.and("service.status").is(status);
}
// 如果有时间范围,添加时间范围匹配规则
if (startTime != null && endTime != null) {
keywordCriteria = keywordCriteria.and("service.timestamp").gte(startTime).lte(endTime);
} else if (startTime != null) {
keywordCriteria = keywordCriteria.and("service.timestamp").gte(startTime);
} else if (endTime != null) {
keywordCriteria = keywordCriteria.and("service.timestamp").lte(endTime);
}
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.match(baseCriteria),
Aggregation.match(keywordCriteria),
Aggregation.sort(Sort.by(Sort.Order.desc("service.timestamp"))),
Aggregation.group("service.identifier")
.first("service.identifier").as("identifier")
.first("service.status").as("status")
.first("service.serviceName").as("serviceName")
.first("service.callType").as("callType")
.first("service.inputParams").as("inputParams")
.first("service.outputParams").as("outputParams")
.first("service.timestamp").as("timestamp")
);
try{
AggregationResults
aggregation, "thingData", ThingData.ServiceData.class);
ThingData.ServiceData data = aggregationResults.getUniqueMappedResult();
servicesData.add(Objects.requireNonNullElseGet(data, () -> new ThingData.ServiceData(serviceSpecDTO.getIdentifier(), serviceSpecDTO.getServiceName(),
null, serviceSpecDTO.getCallType(), serviceSpecDTO.getInputParams(), serviceSpecDTO.getOutputParams(), System.currentTimeMillis())));
} catch (Exception e) {
log.debug("聚合查询失败! 原因" + e);
throw new ServiceException(ServiceException.ExceptionType.INTERNAL_FAILURE,
ExceptionInfoBuilder.build(ExceptionTemplate.INTERNAL_FAILURE_DATABASE,"聚合查询"));
}
}
List
int startIndex = (pageNum - 1) * pageSize;
int endIndex = Math.min(startIndex + pageSize, serviceDataDTOs.size());
List
.skip(startIndex)
.limit(endIndex - startIndex)
.collect(Collectors.toList());
return ResponseDTOBuilder.build(paginatedList, serviceDataDTOs.size(), pageSize, pageNum);
}
需求3.非聚合实现的多条件复杂查询场景:
场景:product{attributes{nodetype; 而我需要进行设备的搜索,设备搜索根据nodetype筛选出一组多个产品,然后根据这组产品的id来得到这些产品下的所有设备;
核心如下:
Query query = new Query();
Criteria criteria = new Criteria();
if (StringUtils.hasText(productId)) {
// 如果提供了 productId,将其作为查询条件
query.addCriteria(Criteria.where("product.id").is(productId));
}
if (StringUtils.hasText(nodeType)) {
//获取符合 nodeType 的所有产品的 productId 列表
Criteria nodeTypeCriteria = Criteria.where("attributes.nodeType").is(nodeType);
List
if (!products.isEmpty()) {
List
for (Product product : products) {
// 将ID添加到查询条件中
orCriteriaList.add(Criteria.where("product.id").is(product.getId()));
}
// 将 Criteria 列表组合成单个 $or 表达式
criteria.orOperator(orCriteriaList.toArray(new Criteria[0]));
}
}
if (StringUtils.hasText(thingStatus)) {
// 如果提供了 thingStatus,将其作为查询条件
query.addCriteria(Criteria.where("status").is(thingStatus));
}
// 如果没有提供关键字,只需执行分页查询,同时过滤掉已删除的设备
query.addCriteria(Criteria.where("deletedAt").is(null));
if (StringUtils.hasText(keyWords)) {
// 如果提供了 keyWords,添加关键字搜索条件
Pattern pattern = Pattern.compile(".*" + keyWords + ".*", Pattern.CASE_INSENSITIVE);
criteria.orOperator(
Criteria.where("name").regex(pattern),
Criteria.where("id").regex(pattern)
);
}
query.addCriteria(criteria);
// 获取符合条件的设备总数
long totalCount = mongoTemplate.count(query, Thing.class);
int skip = (pageNum - 1) * pageSize;
query.skip(skip).limit(pageSize);
try {
List
return ResponseDTOBuilder.build(ThingMapper.INSTANCE.toDTO(things), totalCount, pageSize, pageNum);
} catch (Exception e) {
log.error("查询设备失败" + e);
throw new ServiceException(
ServiceException.ExceptionType.INTERNAL_FAILURE,
ExceptionInfoBuilder.build(ExceptionTemplate.INTERNAL_FAILURE_DATABASE,"查询设备")
);
}
推荐文章
发表评论