You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无法返回Mono<Compliance>求助:如何从MongoDB查询的Mono<PortCall>中过滤Compliance列表并返回目标对象

问题分析与解决方案

首先,咱们来拆解你代码里的几个关键问题,然后一步步修正:

1. 核心问题:误用doOnNext和subscribe()

  • doOnNext是副作用操作符,它只会在流元素通过时执行一些额外逻辑(比如打印日志、更新外部状态),但不会改变流中的元素类型或内容。你原来的代码里,doOnNext里的过滤操作完全没影响到后续的流,流里还是原来的PortCall对象,而不是你想要的Compliance。
  • 直接在Service层调用subscribe()是错误的:subscribe()会立即触发流的执行,返回的是Disposable(用于取消订阅),而不是你需要的Mono<Compliance>。响应式编程的核心是构建流的管道,而不是提前触发执行,订阅应该交给上层调用者(比如WebFlux控制器)来做。

2. 隐藏问题:参数顺序错误

你的Repository方法定义是:

@Query("{vesselCode : ?0, arrivalVoyageCode: ?1}") 
Mono<PortCall> findDeadlineTimestamp(String vesselCode, String arrivalVoyageCode);

但你调用的时候传的是findDeadlineTimestamp(arrivalVoyageCode, vesselCode),参数顺序完全反了!这会导致MongoDB查询时用arrivalVoyageCode匹配vesselCode字段,用vesselCode匹配arrivalVoyageCode字段,大概率查不到数据,这也是你可能拿不到结果的原因之一。

修正后的代码

下面是修复后的Service层代码,完美实现你的需求:

// 注意参数顺序:vesselCode在前,arrivalVoyageCode在后
Mono<Compliance> cmp = portCallRepository.findDeadlineTimestamp(vesselCode, arrivalVoyageCode)
    // 把PortCall转换成匹配的Compliance(或空Mono)
    .flatMap(portCall -> {
        // 过滤Compliance列表,找到第一个匹配compId的元素
        Optional<Compliance> matchingCompliance = portCall.getCompliance().stream()
            .filter(c -> c.getId().equalsIgnoreCase(compId))
            .findFirst();
        // 将Optional转换为Mono:有值则返回Mono.just,无值则返回Mono.empty
        return Mono.justOrEmpty(matchingCompliance);
    });

代码解释:

  • flatMap:用于将流中的PortCall对象转换为另一个Mono<Compliance>,这是响应式编程中转换流类型的正确方式。
  • Optional<Compliance>:用findFirst()获取过滤后的第一个元素,避免空指针问题。
  • Mono.justOrEmpty:把Optional无缝转换成Mono,如果没有匹配的Compliance,返回的Mono会处于empty状态,上层调用者可以通过defaultIfEmpty等操作符处理这种情况。
  • 移除了subscribe():Service层只返回Mono<Compliance>,让上层(比如控制器)来触发订阅,符合响应式编程的最佳实践。

可选的简洁写法

如果你喜欢更紧凑的代码,也可以写成这样:

Mono<Compliance> cmp = portCallRepository.findDeadlineTimestamp(vesselCode, arrivalVoyageCode)
    .map(portCall -> portCall.getCompliance().stream()
        .filter(c -> c.getId().equalsIgnoreCase(compId))
        .findFirst())
    .flatMap(Mono::justOrEmpty);

这样处理后,你就能得到正确的Mono<Compliance>实例了,如果没有匹配的Compliance,Mono会是空的,你可以根据业务需求用defaultIfEmpty(new Compliance(...))来提供默认值。

内容的提问来源于stack exchange,提问作者user2891537

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 16:27:44