2017-06-12 33 views
1

我正在使用AngularJS前端和java後端的JHipster項目。我在MongoDB數據庫中使用Spring Data。在兩個層次上分組操作,每個級別都有一個元素 - 數組關聯

我在一個名爲budgetCode的字符串字段上做了一個分組操作。因此,對於每個budgetCode,都有一個鏈接的taskCodes這是另一個字符串字段的列表。我成功通過另一個#1後要做到這一點:「分組在現場操作,並把喜歡的領域列表陣列中的

這裏,方法aggregateAllTask​​Code它執行分組操作:

存儲庫層

public class ClarityResourceAffectationRepositoryImpl implements ClarityResourceAffectationRepositoryCustom { 
    @Autowired 
    MongoTemplate mongoTemplate; 

    @Override 
    public List<ClarityResourceAffectationReport> aggregateAllTaskCode() { 

     AggregationOperation project = new AggregationOperation() { 
      @Override 
      public DBObject toDBObject(AggregationOperationContext aggregationOperationContext) { 
       return new BasicDBObject("$project", new BasicDBObject("budget_code", "$budget_code").append("task_code", Arrays.asList("$task_code"))); 
      } 
     }; 

     Aggregation aggregation = newAggregation(project, 
       group("budgetCode").addToSet("budgetCode").as("budgetCode").addToSet("taskCode").as("taskCode"), 
       sort(Sort.Direction.ASC, previousOperation(),"budgetCode")); 

     AggregationResults groupResults = mongoTemplate.aggregate(aggregation, ClarityResourceAffectation.class, 
       ClarityResourceAffectationReport.class); 
     List<ClarityResourceAffectationReport> clarityResourceAffectationReports = groupResults.getMappedResults(); 

     return clarityResourceAffectationReports; 
    } 
} 

服務層

public class ClarityResourceAffectationServiceImpl implements ClarityResourceAffectationService{ 
    @Override 
    public List<ClarityResourceAffectationReport> aggregateAllTaskCodes() { 
     log.debug("Request to aggregateAllTaskCodes: {}"); 
     List<ClarityResourceAffectationReport> result = clarityResourceAffectationRepository 
       .aggregateAllTaskCodes(); 

     return result; 
    } 
} 

REST API層

public class ClarityResourceAffectationResource { 
    @GetMapping("/clarity-resource-affectations/list-task-codes") 
    @Timed 
    public ResponseEntity<List<ClarityResourceAffectationReport>> aggregateTabAllTaskCodes() { 
     log.debug("REST request to get aggregateTabAllTaskCodes : {}"); 
     List<ClarityResourceAffectationReport> result = clarityResourceAffectationService.aggregateAllTaskCodes(); 
     return new ResponseEntity<>(result, HttpStatus.OK); 
    } 
} 

這裏,ClarityResourceAffectation和ClarityResourceAffectationReport文件:

ClarityResourceAffectation

@Document(collection = "clarity_resource_affectation") 
public class ClarityResourceAffectation implements Serializable { 

    @Id 
    private String id; 

    @Field("budget_code") 
    private String budgetCode; 

    @Field("task_code") 
    private String taskCode; 

    @Field("action_code") 
    private String actionCode; 

    public String getBudgetCode() { 
     return budgetCode; 
    } 

    public void setBudgetCode(String budgetCode) { 
     this.budgetCode = budgetCode; 
    } 

    public String getTaskCode() { 
     return taskCode; 
    } 

    public void setTaskCode(String taskCode) { 
     this.taskCode = taskCode; 
    } 

    public String getActionCode() { 
     return actionCode; 
    } 

    public void setActionCode(String actionCode) { 
     this.actionCode = actionCode; 
    } 
} 

ClarityResourceAffectationReport

public class ClarityResourceAffectationReport implements Serializable { 

    private static final long serialVersionUID = 1L; 

    private String[] budgetCodes; 
    private String[][] taskCodes; 
    private String[][][] actionCodes; 

    public String[] getBudgetCodes() { 
     return budgetCodes; 
    } 

    public void setBudgetCodes(String[] budgetCodes) { 
     this.budgetCodes = budgetCodes; 
    } 

    public String[][] getTaskCodes() { 
     return taskCodes; 
    } 

    public void setTaskCodes(String[][] taskCodes) { 
     this.taskCodes = taskCodes; 
    } 

    public String[][][] getActionCodes() { 
     return actionCodes; 
    } 

    public void setActionCodes(String[][][] actionCodes) { 
     this.actionCodes = actionCodes; 
    } 
} 

什麼,我在數據庫

/* 0 */ 
{ 
    "_class": "fr.bpce.kpi.clarity.domain.ClarityResourceAffectation", 
    "budget_code": "P24DCDSA01", 
    "task_code": "61427", 
    "action_code": "354" 
} 
/* 1 */ 
{ 
    "_class": "fr.bpce.kpi.clarity.domain.ClarityResourceAffectation", 
    "budget_code": "P24DCDSA01", 
    "task_code": "61427", 
    "action_code": "121" 
} 
/* 2 */ 
{ 
    "_class": "fr.bpce.kpi.clarity.domain.ClarityResourceAffectation", 
    "budget_code": "P24DCDSA01", 
    "task_code": "65434", 
    "action_code": "143" 
} 
/* 3 */ 
{ 
    "_class": "fr.bpce.kpi.clarity.domain.ClarityResourceAffectation", 
    "budget_code": "P24DCDSA01", 
    "task_code": "65434", 
    "action_code": "463" 
} 
/* 4 */ 
{ 
    "_class": "fr.bpce.kpi.clarity.domain.ClarityResourceAffectation", 
    "budget_code": "P24PR00", 
    "task_code": "60298", 
    "action_code": "255" 
} 
/* 5 */ 
{ 
    "_class": "fr.bpce.kpi.clarity.domain.ClarityResourceAffectation", 
    "budget_code": "P24PR00", 
    "task_code": "60298", 
    "action_code": "127" 
} 
/* 6 */ 
{ 
    "_class": "fr.bpce.kpi.clarity.domain.ClarityResourceAffectation", 
    "budget_code": "P24PR00", 
    "task_code": "67875", 
    "action_code": "348" 
} 
/* 7 */ 
{ 
    "_class": "fr.bpce.kpi.clarity.domain.ClarityResourceAffectation", 
    "budget_code": "P24PR00", 
    "task_code": "67875", 
    "action_code": "654" 
} 

眼下的樣本例子,我有一個budgetCode ["P221P00"],鏈接taskCodes [["2630"],["61297"],["61296"],["61299"]]的列表。我想在ClarityResourceAffectationReport文件String[][][]actionCode中添加第三個字段,以便具有另一級別的分組。通過這種方式,taskCodes列表中的每個元素將鏈接到actionCode的列表。在另一個Stackoverflow帖子中,Veeram建議我做兩組,一組在budgetCodetaskCodes上,推actionCode,另一組在budgetCode上,並推送taskCodesactionCode

因此,我開發了一個有兩個項目操作和兩個聚合操作的方法。我不確定這是否是這樣。另外,我不知道如何形成組結果,因爲現在我們有兩個聚合操作。另外,我認爲現在在ClarityResourceAffectationReport中,我有三個數組:String[] budgetCodes, String[][] taskCodes, String[][][] actionCodes

@Override 
public List<ClarityResourceAffectationReport> aggregateAllBudgetCode() { 

     //I did two projects instantiations 
     AggregationOperation projectBudgetTask = new AggregationOperation() { 
      @Override 
      public DBObject toDBObject(AggregationOperationContext aggregationOperationContext) { 
       return new BasicDBObject("$project", new BasicDBObject("budget_code", "$budget_code").append("task_code", Arrays.asList("$task_code"))); 
      } 
     }; 

     AggregationOperation projectTaskAction = new AggregationOperation() { 
      @Override 
      public DBObject toDBObject(AggregationOperationContext aggregationOperationContext) { 
       return new BasicDBObject("$project", new BasicDBObject("task_code", "$task_code").append("action_code", Arrays.asList("$action_code"))); 
      } 
     }; 

     //I did two aggregation methods 
     Aggregation aggregationBudgetTask = newAggregation(projectBudgetTask, 
       group("budgetCode", "taskCode").addToSet("budgetCodeTaskCode").as("budgetCodeTaskCode").addToSet("actionCode").as("actionCode"), 
       sort(Sort.Direction.ASC, previousOperation(),"budgetCode", "taskCode")); 

     Aggregation aggregationTaskAction = newAggregation(projectTaskAction, 
       group("budgetCode").addToSet("budgetCode").as("budgetCode").addToSet("taskCodes").as("taskCodes").addToSet("actionCode").as("actionCode"), 
       sort(Sort.Direction.ASC, previousOperation(),"budgetCode"));   

     //Here, how can I put the two aggregation methods? 
     AggregationResults groupResults = mongoTemplate.aggregate(aggregation, clarityResourceAffectation.class, 
       ClarityResourceAffectationReport.class); 
     List<ClarityResourceAffectationReport> clarityResourceAffectationReport = groupResults.getMappedResults(); 

     return clarityResourceAffectationReport ; 
    } 

在第一聚合操作,我做了group("budgetCode", "taskCode")之後,我把一個addToSet("budgetCodeTaskCode").as("budgetCodeTaskCode")因爲我想考慮到一組操作。但是,實際上我想要做的是group("budgetCode", "taskCode").addToSet("budgetCode", "taskCode").as("budgetCode", "taskCode")。但是,在addToSetas方法中,我們不能放兩個參數。那麼,我們該怎麼做呢?另外,我怎樣才能把這兩種聚合方法放在AggregationResults groupResults

我試過,但它並沒有發揮作用

爲了區分clarityResourceAffectationclarityResourceAffectationReport我加了一個「S」字母在報告類的每個領域。我更新了這篇文章。

在這裏,我有一個聚合操作試圖代碼:

@Override 
public List<ClarityResourceAffectationReport> aggregateAllTaskCode() { 

    AggregationOperation project = new AggregationOperation() { 
     @Override 
     public DBObject toDBObject(AggregationOperationContext aggregationOperationContext) { 
      return new BasicDBObject("$project", new BasicDBObject("task_code", "$task_code").append("action_code", Arrays.asList("$action_code"))); 
     } 
    }; 

    Aggregation aggregation = newAggregation(project, 
       group("budgetCode", "taskCode").addToSet("actionCode").as("actionCodes"), 
       group("budgetCode").first("taskCode").as("taskCode").addToSet(new BasicDBObject("taskCode","$_id.taskCode").append("actionCodes", "$actionCodes")).as("taskCodes"), 
       sort(Sort.Direction.ASC, previousOperation(),"taskCodes")); 

    AggregationResults groupResults = mongoTemplate.aggregate(aggregation, ClarityResourceAffectation.class, 
      ClarityResourceAffectationReport.class); 
    List<ClarityResourceAffectationReport> clarityResourceAffectationReports = groupResults.getMappedResults(); 

    log.debug("clarityResourceAffectationReports.size()" + clarityResourceAffectationReports.size()); 
    log.debug("aggregation.toString()" + aggregation.toString()); 

    return clarityResourceAffectationReports; 
} 

我沒有發揮作用,我有一個錯誤是:f.b.k.l.w.r.errors.ExceptionTranslator : Target bean of type [[Ljava.lang.String; is not of type of the persistent entity ([Ljava.lang.String;)!。無論如何,在第二組之後,你還會在.append("actionCodes", "actionCodes")).as("taskCodeActionCodes")之後加入代碼。你能解釋什麼是taskCodeActionCodes

結果與扁平結構

我變化不大的類型ResourceAffectationReport字段:字符串budgetCodes,字符串[] taskCodes等字符串[] [] actionCodes。

[ 
    { 
    "budgetCodes": "P24D001", 
    "taskCodes": [ 
     "64578" 
    ], 
    "actionCodes": [ 
     [ 
     "454" 
     ], 
     [ 
     "253" 
     ], 
     [ 
     "745" 
     ], 
     [ 
     "354" 
     ] 
    ] 
    }, 
    { 
    "budgetCodes": "P24D002", 
    "taskCodes": [ 
     "62678" 
    ], 
    "actionCodes": [ 
     [ 
     "857" 
     ], 
     [ 
     "907" 
     ], 
     [ 
     "858" 
     ] 
    ] 
    } 
] 

地圖結構

在這裏的結果是,類型報告文件字符串budgetCode的,字符串[] taskCodes,字符串[] [] actionCodes,列表> taskCodesActionCodes。

[ 
    { 
    "budgetCodes": "P24D001", 
    "taskCodes": null, 
    "actionCodes": null, 
    "taskCodesactionCodes": [ 
     { 
     "[Ljava.lang.String;@7e695137": [ 
      [ 
      "64578" 
      ] 
     ], 
     "[Ljava.lang.String;@48ec311a": [ 
      [ 
      "454" 
      ], 
      [ 
      "253" 
      ], 
      [ 
      "745" 
      ], 
      [ 
      "354" 
      ] 
     ] 
     }, 
     { 
     "[Ljava.lang.String;@258b30b6": [ 
      [ 
      "62678" 
      ] 
     ], 
     "[Ljava.lang.String;@481154c7": [ 
      [ 
      "857" 
      ], 
      [ 
      "907" 
      ], 
      [ 
      "858" 
      ] 
     } 
    ] 
    }, 
    { 
    "budgetCodes": "P24D002", 
    "taskCodes": null, 
    "actionCodes": null, 
    "taskCodesActionCodes": [ 
     { 
     "[Ljava.lang.String;@1cdf4a9e": [ 
      [ 
      "64568" 
      ] 
     ], 
     "[Ljava.lang.String;@1613fdbb": [ 
      [ 
      "764" 
      ], 
      [ 
      "984" 
      ], 
      [ 
      "489" 
      ] 
     ] 
     }, 
     { 
     "[Ljava.lang.String;@53167f62": [ 
      [ 
      "63887" 
      ] 
     ], 
     "[Ljava.lang.String;@5a30c8de": [ 
      [ 
      "757" 
      ], 
      [ 
      "394" 
      ], 
      [ 
      "294" 
      ], 
      [ 
      "765" 
      ] 
     ] 
     } 
    ] 
    } 
] 

的地圖結構的方法是有趣的,但我在爲了顯示在我的前端的一些問題,但是這是因爲這是對象類型的鍵的另一問題。我會再次測試,我會告訴你。無論如何,它是Interresting。其實,我有另一個想法。我想要的是,在每個JSON文檔中,我有一個字符串字段budgetCodes,一個字符串[]字段taskCodes,其中將包含鏈接到budgetCodes的所有 taskCodes,我認爲最終真正適用於我想要創建的TaskCode類這樣的:

public class TaskCode { 
    private String taskCode; 
    private String[] actionCode; 

    //Getters and Setters 
} 

通過這種方式,可以讓我爲每個JSON文件,一個簡單的字符串與budgetCode,與 每個taskCode對象鏈接TaskCodes的列表中,字符串屬性taskCode這將包含taskCode的值。最後,每個taskCode對象將包含一個帶有actionCodes列表的String [] 。

關於POJO結構

它的功能良好,但我在爲了顯示在AngularJS前端的數據的一些問題。我想要做一個聚合操作來創建一個菜單,其中每次點擊一個元素將打開一個子菜單和一個子列表,等等......我不知道一個聚合是否真的適應我想要做的事情。所以,我想到了另一種方法。也許另一種方法可能是通過數據庫中的簡單查找操作來檢索我想要的數據,並使用服務層來完成樹算法。

在此先感謝

+0

這可能會是一個更加清晰,如果你表現出一定的樣本文件和輸出你期望從他們得到。目前這個問題結構的危險在於你的「嘗試」可能完全沒有達到你需要的結果標記。這就是爲什麼通常最好是*「通過示例問問」*因此有一個明確的「來源」和「結果」。另外,請不要在項目的每個組件上「標記」您的問題。根據實際問題的應用標籤,您只是詢問「spring-mongo」和「聚合框架」**。 –

+0

我明白你的意思。實際上,我只想在2個級別上進行分組,因爲每個結果都必須放在一個子數組中。這就是爲什麼'ClarityResourceAffection'(對於輸入字段)有三個字符串字段:String budgetCode,String taskCode,String actionCode和ClarityResourceAffectionReport(對於輸出字段),有三個數組'String [ ] budgetCode,String [] [] taskCode,String [] [] [] actionCode'。通過這種方式,'String [] budgetCode'將包含所有的budgetCodes,'String [] [] taskCode'將包含每個budgetCode的任務代碼列表等等。 – henry22

+0

您知道我們無法從這裏看到您的計算機屏幕。所以我要求你展示一些數據和期望的結果。你的代碼沒有很好地解釋這一點。編輯你的問題,請包括文件。 –

回答

0

您可以在單個聚合管道中執行多個級別分組。

已更新的現有項目階段包括actionCode並更新現有組以包含actionCode

這將顯示flatten結構,每行包含budgetCodes,taskCodesactionCodes

更新您的actionCodesprivate String[][] actionCodes;

扁平結構。

喜歡的東西

AggregationOperation project = new AggregationOperation() { 
    @Override 
    public DBObject toDBObject(AggregationOperationContext aggregationOperationContext) { 
     return new BasicDBObject("$project", new BasicDBObject("budget_code", 1).append("task_code", Arrays.asList("$task_code")).append("action_code", Arrays.asList("$action_code"))); 
     } 
    }; 

Aggregation aggregation = newAggregation(project, 
     group("budgetCode", "taskCode").addToSet("actionCode").as("actionCodes"), 
     project("actionCodes").and("_id.budgetCode").as("budgetCodes").and("_id.taskCode").as("taskCodes").andExclude("_id"), 
     sort(Sort.Direction.ASC, "budgetCodes","taskCodes")); 

地圖狀結構。

調整你的輸出DTO到

private String[] budgetCodes; 
private List<Map<String[], String[][]>> taskCodeActionCodes; 

這將輸出結果到地圖給你多個分組。

喜歡的東西

AggregationOperation project = new AggregationOperation() { 
    @Override 
    public DBObject toDBObject(AggregationOperationContext aggregationOperationContext) { 
     return new BasicDBObject("$project", new BasicDBObject("budget_code", 1).append("task_code", Arrays.asList("$task_code")).append("action_code", Arrays.asList("$action_code"))); 
    } 
    }; 

Aggregation aggregation = newAggregation(project, 
     group("budgetCode", "taskCode").addToSet("actionCode").as("actionCodes"), 
     group("_id.budgetCode").addToSet(new BasicDBObject("taskCode","$_id.taskCode").append("actionCodes", "$actionCodes")).as("taskCodeActionCodes"), 
      project("taskCodeActionCodes").and("budgetCodes").previousOperation().andExclude("_id"), 
     sort(Sort.Direction.ASC, "budgetCodes")); 

POJO結構

public class ClarityResourceAffectationReport { 

    private String budgetCode; 
    private List<TaskCode> linkedTaskCodes; 
} 


public class TaskCode { 
    private String taskCode; 
    private String[] actionCode; 

} 

Aggregation aggregation = newAggregation(
      group("budgetCode", "taskCode").addToSet("actionCode").as("actionCode"), 
      group("_id.budgetCode").addToSet(new BasicDBObject("taskCode","$_id.taskCode").append("actionCode", "$actionCode")).as("linkedTaskCodes"), 
       project("linkedTaskCodes").and("budgetCode").previousOperation().andExclude("_id"), 
     sort(Sort.Direction.ASC, "budgetCode")); 
+0

我更新了帖子。我把我的嘗試,但我不明白一些事情,例如你在第二組操作中使用的'taskCodeActionCodes'變量。另外,我不知道爲什麼你沒有像在AggregationOperation項目中那樣放置,''task_code'和'action_code'在aggretation操作的'new BasicDBObject'中。相反,你把'taskCode,$ _id.taskCode'和'actionCodes,actionCodes'。 – henry22

+0

對不起,我可能在這裏錯過了一些東西。我根據反饋更新了答案。看起來你需要一個平坦的結果,你不需要第二組。結果將按預算代碼和任務代碼以及相應的操作代碼進行分組。如果需要第二組,則必須使用類似數據結構的映射來映射任務代碼和操作代碼之間的關係。 – Veeram

+0

感謝您的更新。你確定你可以像使用聚合方法中的第二次調用一樣使用'project'嗎?因爲在我的Eclipse中,project(「actionCodes」)和(「_ id.budgetCode」)...的'project'關鍵字用紅色加下劃線,就像我們不能像這樣使用'project'。 – henry22

相關問題