spring-data-mongodb icon indicating copy to clipboard operation
spring-data-mongodb copied to clipboard

if there is no data "getUniqueMappedResult" throws an exception

Open blueiceprj opened this issue 3 years ago • 2 comments

Hello,

If you add a new function with Optional value return its would be useful to control return value.

Current Implementation and throw an exception if there is no data

	@Nullable
	public T getUniqueMappedResult() {
		Assert.isTrue(mappedResults.size() < 2, "Expected unique result or null, but got more than one!");
		return mappedResults.size() == 1 ? mappedResults.get(0) : null;
	}

Optional<T> ..... Thanks

blueiceprj avatar Jan 10 '22 19:01 blueiceprj

Please spend a bit more time describing your request (maybe outline the usage scenario you have in mind). Right now, we struggle to understand what you want to achieve.

christophstrobl avatar Jan 11 '22 08:01 christophstrobl

Hi, Ok. I try to explain on my case and solution.

	public StudentAttendanceDTO getAttendance(StudentAttendanceSearchDTO dto)
	{
		final List<AggregationOperation> pipeline =new ArrayList<>();
		pipeline.add(Aggregation.group("info.studentId").count().as("courseEventsPlanned") 
				.sum(ConditionalOperators.Cond.when(Criteria.where("info.type").is(AttendanceType.PRESENT)).then(1).otherwise(0))
				.as("courseEventsAttended")
				..................
                                ...................................
                final AggregationResults<R> aggregate = template.aggregate(pipeline, collectionName, outputClass);
		return uniqueResult(collectionName, AttendanceDTO.class,
				Aggregation.newAggregation(pipeline));
	}

       // I have to use this method to return without exception. This my solution
       private <R> R getUniqueResult(final AggregationResults<R> aggregate)
	{
		List<R> results = aggregate.getMappedResults();
		if (isNotEmpty(results))
		{
			return results.get(0);
		} else
		{
			return null;
		}
	}

       // If I need optional version I use this
       protected <R> Optional<R> getUniqueResultOf(final AggregationResults<R> aggregate)
	{
		List<R> results = aggregate.getMappedResults();
		if (isNotEmpty(results))
		{
			return Optional.of(results.get(0));
		} else
		{
			return Optional.empty();
		}
	}

instead of this implementation

       public Optional<StudentAttendanceDTO> getAttendance(StudentAttendanceSearchDTO dto)
	{
		final List<AggregationOperation> pipeline =new ArrayList<>();
		pipeline.add(Aggregation.group("info.studentId").count().as("courseEventsPlanned") 
				.sum(ConditionalOperators.Cond.when(Criteria.where("info.type").is(AttendanceType.PRESENT)).then(1).otherwise(0))
				.as("courseEventsAttended")
				..................
                                ...................................
                final AggregationResults<R> aggregate = template.aggregate(pipeline, collectionName, outputClass);
               // It throws an exception if there is no data 
		return aggregate.getUniqueMappedResult();
             // It would be very useful if you add to new version of this method like this
               return aggregate.getUniqueMappedResultOf(); // optional and return object as Optional<StudentAttendanceDTO>
	}

blueiceprj avatar Jan 12 '22 14:01 blueiceprj

Sorry for long silence. We've been revisiting the issue and will not add an additional method returning Optional<T> to AggregationResults. Optional.ofNullable(result.getUniqueMappedResult()) should be sufficient to support the described use case.

christophstrobl avatar Mar 10 '23 12:03 christophstrobl