场景:一个设备的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 propertiesData = new ArrayList<>();

// 创建一个空的关键字条件

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 aggregationResults = mongoTemplate.aggregate(

aggregation,"thingData", ThingData.PropertyData.class);

List matchingData = aggregationResults.getMappedResults();

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 propertyDataDTOs = ThingDataMapper.INSTANCE.toPropertyDTO(propertiesData);

int startIndex = (pageNum - 1) * pageSize;

int endIndex = Math.min(startIndex + pageSize, propertyDataDTOs.size());

List paginatedList = propertyDataDTOs.stream()

.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 servicesData = new ArrayList<>();

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 aggregationResults = mongoTemplate.aggregate(

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 serviceDataDTOs = ThingDataMapper.INSTANCE.toServiceDTO(servicesData);

int startIndex = (pageNum - 1) * pageSize;

int endIndex = Math.min(startIndex + pageSize, serviceDataDTOs.size());

List paginatedList = serviceDataDTOs.stream()

.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 products = mongoTemplate.find(Query.query(nodeTypeCriteria), Product.class);

if (!products.isEmpty()) {

List orCriteriaList = new ArrayList<>();

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 things = mongoTemplate.find(query, Thing.class);

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,"查询设备")

);

}

推荐文章

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: