【问题标题】:MongoDB projection on an @Aggregation spring data@Aggregation 春季数据上的 MongoDB 投影
【发布时间】:2020-11-12 14:16:27
【问题描述】:

我已经为此苦苦挣扎了几天。我们刚刚开始使用 mongoDB,因此我对它的了解非常有限。

无论如何,这就是我想做的:我们有一个像这样的名为 Loan 的类:

@Document(collection = "Loans")
public class Loan{

    @Id
    private String id;
    private String type;

    private LoanApplication loanApplication;
    private LoanDecision loanDecision;

    private String loanAppId;
    private String loanDecisionId;

    private LocalDateTime receivedDate;
    private LocalDate leadExpiry;

    private Integer previousStatus;
    private Integer status;

    private Boolean isEligibleForRemove;

    private String timeStamp;

    private List<String> loanDecisions;

    private String activeLoanDecision;
    private String lenderReferenceNumber;
    private String pdfName;

因为我们在查询这个集合时必须执行各种操作,所以我们在 LoanRepository 中创建了一个聚合(我们在 Mongo Compass 中创建的聚合工作,然后将其导出到我们的代码中):

@Repository
@EnableMongoRepositories
public interface LoanRepository extends MongoRepository<Loan, String> {

@Aggregation(pipeline = {"{$match: {\r\n" + 
        "  'status':{$in: ?0},\r\n" + 
        "  'loanApplication.mortgage.requested.lenderSubmission.lenderProfile.lenderCode': ?1\r\n" + 
        "  }},{\r\n" + 
        "    $project: {\r\n" + 
        "        'applicationId': '$loanApplication.deal.applicationId',\r\n" + 
        "        'cominedLtv': '$loanApplication.deal.combinedLtv',\r\n" + 
        "        'receivedDate': '$receivedDate',\r\n" + 
                 //other fields to project
        "        }\r\n" + 
        "    }\r\n" + 
        "}, {\r\n" + 
        "    $unwind: {\r\n" + 
        "        path: '$applicants'\r\n" + 
        "    }\r\n" + 
        "}, {\r\n" + 
        "    $match: {\r\n" + 
        "        'applicants.primaryApplicantFlag': 'Y'\r\n" + 
        "    }\r\n" + 
        "}
         //other aggregate methods
"})
    public List<LoanProjection> findLeads(final List<Integer> leadsStatus, final String lenderCode);
}

想法是,在完成上述所有操作后,我们只需要从整个 Loans 表中返回一些字段(如 $project 步骤所示)。我知道这个存储库中所有方法的返回类型必须是 Loan,一种解决方案是利用 spring 投影。因此,我创建了必要的投影接口(下面您将只找到 $project 步骤中字段的接口):

public interface LoanProjection {   
    DealType getDealType();
    LocalDate getReceivedDate();
}

public interface DealTypeProjection {
    String getApplicationId();
    String getcombinedLtv();
}

问题是:调用findLeads()存储库方法时出现以下错误:

java.lang.NullPointerException: null
    at org.springframework.data.mongodb.core.mapping.MongoSimpleTypes$1.isSimpleType(MongoSimpleTypes.java:110) ~[spring-data-mongodb-2.2.5.RELEASE.jar:2.2.5.RELEASE]
    at org.springframework.data.mongodb.repository.query.StringBasedAggregation.isSimpleReturnType(StringBasedAggregation.java:119) ~[spring-data-mongodb-2.2.5.RELEASE.jar:2.2.5.RELEASE]
    at org.springframework.data.mongodb.repository.query.StringBasedAggregation.doExecute(StringBasedAggregation.java:81) ~[spring-data-mongodb-2.2.5.RELEASE.jar:2.2.5.RELEASE]
    at org.springframework.data.mongodb.repository.query.AbstractMongoQuery.execute(AbstractMongoQuery.java:101) ~[spring-data-mongodb-2.2.5.RELEASE.jar:2.2.5.RELEASE]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:618) ~[spring-data-commons-2.2.5.RELEASE.jar:2.2.5.RELEASE]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:605) ~[spring-data-commons-2.2.5.RELEASE.jar:2.2.5.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:80) ~[spring-data-commons-2.2.5.RELEASE.jar:2.2.5.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95) ~[spring-aop-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at com.sun.proxy.$Proxy130.findLeadsTest(Unknown Source) ~[na:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_231]
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_231]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_231]
    at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_231]
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) ~[spring-tx-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at com.sun.proxy.$Proxy130.findLeadsTest(Unknown Source) ~[na:na]
    at com.filogix.lg.service.impl.LoanServiceImpl.retrieveLeads(LoanServiceImpl.java:261) ~[classes/:na]
    at com.filogix.lg.api.LoanController.getLeads(LoanController.java:49) ~[classes/:na]
    at com.filogix.lg.api.LoanController$$FastClassBySpringCGLIB$$54fe4fe8.invoke(<generated>) ~[classes/:na]
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:769) ~[spring-aop-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747) ~[spring-aop-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:120) ~[spring-context-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747) ~[spring-aop-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689) ~[spring-aop-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at com.filogix.lg.api.LoanController$$EnhancerBySpringCGLIB$$f692749f.getLeads(<generated>) ~[classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_231]
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_231]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_231]
    at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_231]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106) ~[spring-webmvc-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879) ~[spring-webmvc-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793) ~[spring-webmvc-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:634) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.31.jar:9.0.31]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
    at com.filogix.lg.config.DecodingFilter.doFilter(DecodingFilter.java:35) ~[classes/:na]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-9.0.31.jar:9.0.31]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) [tomcat-embed-core-9.0.31.jar:9.0.31]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) [tomcat-embed-core-9.0.31.jar:9.0.31]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.31.jar:9.0.31]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.31.jar:9.0.31]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.31.jar:9.0.31]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367) [tomcat-embed-core-9.0.31.jar:9.0.31]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.31.jar:9.0.31]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) [tomcat-embed-core-9.0.31.jar:9.0.31]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1639) [tomcat-embed-core-9.0.31.jar:9.0.31]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.31.jar:9.0.31]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [na:1.8.0_231]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [na:1.8.0_231]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.31.jar:9.0.31]
    at java.lang.Thread.run(Unknown Source) [na:1.8.0_231]

我首先开始修剪我的聚合逻辑,认为它可能存在问题(聚合在 Mongo Compass 和 Atlass 中工作正常),我最终只有 $match 运算符(一些非常基本的东西),但错误仍然存​​在.

@Aggregation(pipeline = {"{$match: {\r\n" + 
            "  'status':{$in: ?0},\r\n" + 
            "  'loanApplication.mortgage.requested.lenderSubmission.lenderProfile.lenderCode': ?1\r\n" + 
            "  }}"})
    public List<LoanProjection> findLeadsTest(final List<Integer> leadsStatus, final String lenderCode);

然后我想看看通过使用@Query 注释是否会收到相同的错误。用这种方法投影很有趣!!!

@Query(value = "{$and: [{'status': {$in: ?0}}, {'loanApplication.mortgage.requested.lenderSubmission.lenderProfile.lenderCode': ?1}]}")
    public List<LoanProjection> findLeads(final List<Integer> leadsStatus, final String lenderCode);

因此我的问题是:不知何故春季投影与@Agregation 不兼容,还是我使用错了(很可能)?

【问题讨论】:

    标签: java mongodb spring-boot aggregation-framework spring-data-mongodb


    【解决方案1】:

    我认为您需要使用class 而不是interface,并且您需要添加@Id 注释以匹配聚合结果

    在您的情况下,很难准确地遵循 id,因为您没有通过 CLI 在 mongo 中手动运行聚合添加任何结果。

    但是,如果我尝试猜测,那么这样的事情可能会对您有所帮助:

    import org.springframework.data.annotation.Id;
    // other imports
    
    public class LoanProjection {
    
        @Id
        private DealType dealType;
        private LocalDate receivedDate;
    
        DealType getDealType() {
            return dealType;
        }
    
        LocalDate getReceivedDate() {
            return receivedDate;
        }
    }
    
    public class DealTypeProjection {
        @Id
        private String applicationId;
        private String combinedLtv;
    
        public String getApplicationId() {
            return applicationId;
        }
    
        public String getCombinedLtv() {
            return combinedLtv;
        }
    }
    

    通常聚合的结果与使用的Document 非常不同,因此您需要有一些唯一标识符才能将其映射到新的Projection。您可以像查看新的 Document 一样查看聚合结果,因为这是 spring 将结果与实际 DTO 匹配的方式。

    更多细节在这里: https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mongodb.repositories.queries.aggregation

    【讨论】:

      猜你喜欢
      • 2018-03-29
      • 1970-01-01
      • 2018-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-01
      • 1970-01-01
      相关资源
      最近更新 更多