Making Date queries on MongoDB using JSON on SpringDataMongoDB

独自空忆成欢 提交于 2019-12-25 01:39:43

问题


I'm having some trouble making MongoDB Date queries using @Query annotation on SpringDataMongoDB on a project created using JHipster.

Since JHipster was used to create the project most of the queries were created using Spring Data query builder mechanism and for more refined queries, instead of using Type-safe Query methods I decided to stick with JHipster's standard configuration and make personalized queries using @Query annotation that allows the creation of MongoDBJSON queries.

However, I can't reference in my Json queries any entity field of type Date or LocalDate.

I tried to adopt as a solution the answer from this thread without success.

Query attempts

@Repository
public interface CourseClassRepository extends MongoRepository<CourseClass, String> {

    // WORKS - query with `endDate` directly constructed by Spring Data
    // This sollution however isn't enought, since 'experience_enrollments.device_id' cannot be used as a parameter
    List<CourseClass> findAllByInstitutionIdAndEndDateIsGreaterThanEqual(Long institutionId, LocalDate dateLimit);

    // Using @Query to create a JSON query doesn't work.
    // apparently data parameter cannot be found. This is weird, considering that in any other @Query created the parameter is found just fine.
    // ERROR: org.bson.json.JsonParseException: Invalid JSON input. Position: 124. Character: '?'
    @Query(" { 'experience_enrollments.device_id' : ?0, 'institution_id': ?1, 'end_date': { $gte: { $date: ?2 } } } ")
    List<CourseClass> findAllByExperienceDeviceAndInstitutionIdAndEndDate(String deviceId, Long institutionId, Date dateLimit);

    // Adopting the stackoverflow answer mentioned above also throws an error. I belive that this error is related to the fact that '?2' is being interpreted as a String value and not as reference to a parameter
    // ERROR: org.bson.json.JsonParseException: Failed to parse string as a date
    @Query(" { 'experience_enrollments.device_id' : ?0, 'institution_id': ?1, 'end_date': { $gte: { $date: '?2' } } } ")
    List<CourseClass> findAllByExperienceDeviceAndInstitutionIdAndEndDate(String deviceId, Long institutionId, Date dateLimit);

    // Even hardcoding the date parameter, the query throws an error
    // ERROR: org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class java.time.ZonedDateTime.
    @Query(" { 'experience_enrollments.device_id' : ?0, 'institution_id': ?1, 'end_date': { '$gte': { '$date': '2015-05-16T07:55:23.257Z' } } }")
    List<CourseClass> findAllByExperienceDeviceAndInstitutionIdAndEndDate(String deviceId, Long institutionId);
}

Database Configurations

@Configuration
@EnableMongoRepositories("br.com.pixinside.lms.course.repository")
@Profile("!" + JHipsterConstants.SPRING_PROFILE_CLOUD)
@Import(value = MongoAutoConfiguration.class)
@EnableMongoAuditing(auditorAwareRef = "springSecurityAuditorAware")
public class DatabaseConfiguration {
     @Bean
        public MongoCustomConversions customConversions() {
            List<Converter<?, ?>> converters = new ArrayList<>();
            converters.add(DateToZonedDateTimeConverter.INSTANCE);
            converters.add(ZonedDateTimeToDateConverter.INSTANCE);
            return new MongoCustomConversions(converters);
        }
}

Date converters

    public static class DateToZonedDateTimeConverter implements Converter<Date, ZonedDateTime> {

        public static final DateToZonedDateTimeConverter INSTANCE = new DateToZonedDateTimeConverter();

        private DateToZonedDateTimeConverter() {
        }

        @Override
        public ZonedDateTime convert(Date source) {
            return source == null ? null : ZonedDateTime.ofInstant(source.toInstant(), ZoneId.systemDefault());
        }
    }

    public static class ZonedDateTimeToDateConverter implements Converter<ZonedDateTime, Date> {

        public static final ZonedDateTimeToDateConverter INSTANCE = new ZonedDateTimeToDateConverter();

        private ZonedDateTimeToDateConverter() {
        }

        @Override
        public Date convert(ZonedDateTime source) {
            return source == null ? null : Date.from(source.toInstant());
        }
    }

回答1:


Turns out that, as mentioned by Christoph Strobl, the behavior was, in fact, a bug. So it won't be necessary to worry about that in a future version of Spring Data MongoDB. Until there, I'm sharing my solution.

Since I was unable to use MongoDBJSon to create the query, I used the MongoTemplate and everything was just fine.

import org.springframework.data.mongodb.core.MongoTemplate;
import static org.springframework.data.mongodb.core.query.Criteria.where;
import static org.springframework.data.mongodb.core.query.Query.query;   

    @Autowired
    public MongoTemplate mongoTemplate;

    public List<CourseClass> findEnrolledOnExperienceDeviceWithMaxEndDateAndInstitutionId(String deviceId, LocalDate endDate, Long institutionId) {
        return mongoTemplate.find(query(
            where("experience_enrollments.device_id").is(deviceId)
                .and("institution_id").is(institutionId)
                .and("end_date").gte(endDate)), CourseClass.class);
    }


来源:https://stackoverflow.com/questions/56862718/making-date-queries-on-mongodb-using-json-on-springdatamongodb

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!