Project Reactor条件执行:MongoDB存储前关联对象存在性校验
Great question! Let's walk through how to implement this non-blocking validation using Project Reactor, which plays perfectly with reactive MongoDB repositories. The key is to avoid blocking calls like block() and instead use Reactor's operators to compose asynchronous checks seamlessly.
Core Approach
We need to:
- Extract the IDs of the sub-objects from your main object
- Asynchronously check if each sub-object exists in its respective collection
- Validate all checks pass before proceeding to save the main object
- Throw a meaningful exception if any sub-object is missing
Example Implementation
Let's assume you have reactive repositories for your sub-objects (e.g., SubObject1Repository and SubObject2Repository) and a main object repository (MainObjectRepository).
First, define your object structures and sample input:
// Your main object and sub-object reference structure record MainObject(String id, SubObjectRef subobject1, SubObjectRef subobject2) {} record SubObjectRef(String id) {} // Sample input object to validate and save MainObject inputObject = new MainObject("123", new SubObjectRef("1"), new SubObjectRef("2"));
Now, compose the reactive validation and save flow:
// Step 1: Create asynchronous existence checks for each sub-object Mono<Boolean> sub1Exists = subObject1Repository.existsById(inputObject.subobject1().id()); Mono<Boolean> sub2Exists = subObject2Repository.existsById(inputObject.subobject2().id()); // Step 2: Combine checks and validate results Mono<MainObject> validatedSaveFlow = Mono.zip(sub1Exists, sub2Exists) .flatMap(existenceTuple -> { boolean isSub1Present = existenceTuple.getT1(); boolean isSub2Present = existenceTuple.getT2(); if (!isSub1Present) { return Mono.error(new RuntimeException("Subobject1 with ID " + inputObject.subobject1().id() + " does not exist")); } if (!isSub2Present) { return Mono.error(new RuntimeException("Subobject2 with ID " + inputObject.subobject2().id() + " does not exist")); } // All checks passed: return the valid object for saving return Mono.just(inputObject); }) // Step 3: Save the main object if validation passes .flatMap(mainObjectRepository::save);
Key Notes
- Parallel Execution:
Mono.zipruns both existence checks in parallel, which is more efficient than serializing them with nestedflatMapcalls - Non-blocking: No
block()calls here — the entire flow stays asynchronous, letting Reactor manage thread scheduling without blocking - Error Handling: Using
Mono.error()properly signals failure in the reactive stream, which you can handle downstream with operators likeonErrorResumeoronErrorMapto customize error responses
Handling Multiple Sub-Objects
If you have more than two sub-objects, scale this approach using Flux to batch checks:
// Example with a list of sub-object IDs List<String> subObjectIds = List.of("1", "2", "3"); // Create a flux of asynchronous existence checks Flux<Boolean> allExistenceChecks = Flux.fromIterable(subObjectIds) .flatMap(subId -> subObjectRepository.existsById(subId)); // Validate all sub-objects exist Mono<Boolean> allSubObjectsExist = allExistenceChecks.all(exists -> exists); // Integrate into your save flow Mono<MainObject> bulkValidatedFlow = allSubObjectsExist .flatMap(allExist -> { if (!allExist) { return Mono.error(new RuntimeException("One or more sub-objects are missing")); } return Mono.just(inputObject); }) .flatMap(mainObjectRepository::save);
Remember to keep the entire chain reactive — avoid breaking it with blocking calls, as that defeats the purpose of using Project Reactor for non-blocking operations.
内容的提问来源于stack exchange,提问作者Вадим Парафенюк

