使用Spring数据获取空指针异常Mongo聚合(动态字段)

时间:2016-12-27 13:43:28

标签: spring mongodb spring-data

这是我的Mongo Pojo也是getter和setters(未添加)。

    @CompoundIndex(name = "account_date_idx", def = "{'account' : 1, 'date' : 1}", unique = true)
@Document(collection = "agent_data_storage")
public class AgentDataStorage extends MongoKeyedEntity<String> implements Serializable {

  public static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
  @Field
  private Long account;

  @Field()
  private String date;

  @Field
  private Map<String, Double> dataPoints = new HashMap<>();

  public AgentDataStorage() {
  }

  public AgentDataStorage(Long account) {
    this.account = account;
    this.date = dateFormat.format(new Date());
    for (AgentDataPoints dataPoint : EnumSet.allOf(AgentDataPoints.class)) {
      this.dataPoints.put(dataPoint.toString(), 0d);
    }
  }

  public AgentDataStorage(String account) {
    this.account = Long.valueOf(account);
    for (AgentDataPoints dataPoint : EnumSet.allOf(AgentDataPoints.class)) {
      this.dataPoints.put(dataPoint.toString(), 0d);
    }
  }

  public AgentDataStorage(Long account, Date date) {
    this.account = account;
    this.date = dateFormat.format(date);
    for (AgentDataPoints dataPoint : EnumSet.allOf(AgentDataPoints.class)) {
      this.dataPoints.put(dataPoint.toString(), 0d);
    }
  }

  public AgentDataStorage(Long account, Date date, Map<String, Double> dataPoints) {
    this.account = account;
    this.date = dateFormat.format(date);
    this.dataPoints = dataPoints;
  }

  public AgentDataStorage(Long account, String date, Map<String, Double> dataPoints) {
    this.account = account;
    this.date = date;
    this.dataPoints = dataPoints;
  }

  public AgentDataStorage(String account, Date date) {
    this.account = Long.valueOf(account);
    this.date = dateFormat.format(date);
    for (AgentDataPoints dataPoint : EnumSet.allOf(AgentDataPoints.class)) {
      this.dataPoints.put(dataPoint.toString(), 0d);
    }
  }

  public AgentDataStorage(String account, String date) {
    this.account = Long.valueOf(account);
    this.date = date;
    for (AgentDataPoints dataPoint : EnumSet.allOf(AgentDataPoints.class)) {
      this.dataPoints.put(dataPoint.toString(), 0d);
    }
  }

  public Long getAccount() {
    return account;
  }

  public void setAccount(Long account) {
    this.account = account;
  }

  public Date getDate() throws ParseException {
    return dateFormat.parse(this.date);
  }

  public void setDate(Date date) {
    this.date = dateFormat.format(date);
  }

  public Map<String, Double> getDataPoints() {
    return dataPoints;
  }

  public void setDataPoints(Map<String, Double> dataPoints) {
    this.dataPoints = dataPoints;
  }

  public void updateDataPoint(AgentDataPoints agentDataPoints, Double value) {
    this.dataPoints.put(String.valueOf(agentDataPoints), value);
  }

  @Override
  public String toString() {
    final StringBuilder sb = new StringBuilder("AgentDataStorage{");
    sb.append("account=").append(account);
    sb.append(", date=").append(date);
    sb.append(", dataPoints=").append(dataPoints);
    sb.append('}');
    return sb.toString();
  }
}

尝试聚合时,我得到空指针异常,下面是我的测试用例。

     @Test
  public void aggregationTest() {
    Long account = 12121l;
    String startDay = "2016-01-01";
    String endDay = "2016-01-03";

    Aggregation aggregation = Aggregation
        .newAggregation(match(Criteria.where("account").is(account).and("date")
            .gte(startDay).lte(endDay)),
            group("account").sum("dataPoints.TOTAL_BUS_COMMISSION").as("total"));
    AggregationResults<AggregationResult> results = mongoTemplate.aggregate(aggregation,
        AgentDataStorage.class, AggregationResult.class);

  }

我的AggregationResult类是 -

public class AggregationResult {

  private Long _id;

  private Double total;

  public Long get_id() {
    return _id;
  }

  public void set_id(Long _id) {
    this._id = _id;
  }

  public Double getTotal() {
    return total;
  }

  public void setTotal(Double total) {
    this.total = total;
  }
}

下面是Stack Trace of Error

java.lang.NullPointerException
    at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentPropertyPath(AbstractMappingContext.java:233)
    at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentPropertyPath(AbstractMappingContext.java:214)
    at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentPropertyPath(AbstractMappingContext.java:210)
    at org.springframework.data.mongodb.core.aggregation.TypeBasedAggregationOperationContext.getReferenceFor(TypeBasedAggregationOperationContext.java:96)
    at org.springframework.data.mongodb.core.aggregation.TypeBasedAggregationOperationContext.getReference(TypeBasedAggregationOperationContext.java:91)
    at org.springframework.data.mongodb.core.aggregation.GroupOperation$Operation.getValue(GroupOperation.java:434)
    at org.springframework.data.mongodb.core.aggregation.GroupOperation$Operation.toDBObject(GroupOperation.java:416)
    at org.springframework.data.mongodb.core.aggregation.GroupOperation.toDBObject(GroupOperation.java:361)
    at org.springframework.data.mongodb.core.aggregation.Aggregation.toDbObject(Aggregation.java:331)
    at org.springframework.data.mongodb.core.MongoTemplate.aggregate(MongoTemplate.java:1500)
    at org.springframework.data.mongodb.core.MongoTemplate.aggregate(MongoTemplate.java:1435)
    at psl.service.core.agentanalytics.internal.AgentAnalyticsServiceTest.aggregationTest(AgentAnalyticsServiceTest.java:132)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:72)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:81)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:216)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:82)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:60)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:67)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:162)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:119)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)

我也尝试调试内部的spring jar,它在AbstractMappingContext.java中为Double类型抛出null,但是不能理解它为什么会发生。 mongo控制台正在使用相同的mongo查询。

db.getCollection('agent_data_storage').aggregate([ 
{ "$match" : { "account" : 12121 , "date" : { "$gte" : "2016-01-01" , "$lte" : "2016-01-03"}}} 
, { "$group" : { "_id" : "$account" , "total" : { "$sum" : "$dataPoints.TOTAL_BUS_COMMISSION"}}}])

上述查询的结果是

 {
    "_id" : NumberLong(12121),
    "total" : 402.0
}

感谢您提供任何帮助。

来自AgentDataStorage的示例文档 -

{
    "_id" : ObjectId("586233e3fb94f6f5640196cf"),
    "account" : NumberLong(12121),
    "date" : "2016-01-01",
    "dataPoints" : {
        "TOTAL_BUS_COMMISSION" : 0.0
    }
}

1 个答案:

答案 0 :(得分:2)

不要使用聚合的类型聚合变体,它主要是尝试将输入类型(AgentDataStorage)中的属性引用转换为字段名称,并且在它没有找到属性引用时失败,在您的情况下dataPoints.TOTAL_BUS_COMMISSION。

使用

AggregationResults<AggregationResult> results = mongoTemplate.aggregate(aggregation,
    "agent_data_storage", AggregationResult.class);