在两个级别上对操作进行分组,每个级别都有一个元素 - 数组关联

Grouping operations on two levels with for each level an element - array association

我正在使用 AngularJS 前端和 java 后端开发 JHipster 项目。我在 MongoDB 数据库中使用 Spring 数据。

我对名为 budgetCode 的字符串字段进行了分组操作。因此,对于每个 budgetCode,都有一个链接的列表 taskCodes,这是另一个字符串字段。我通过另一个 Whosebug post 成功地做到了这一点:“对字段进行分组操作并将喜欢的字段列表放入数组中

这里,做分组操作的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;
    }
}

休息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"
}

目前,我有一个预算代码 ["P221P00"],一个链接的任务代码列表 [["2630"],["61297"],["61296"],["61299"]]。我想在 ClarityResourceAffectationReport 文件 String[][][]actionCode 中添加第三个字段,以便进行另一级别的分组。通过这种方式,taskCodes 列表的每个元素都将链接到 actionCode 的列表。在另一个 Whosebug post 中,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我在报告class的每个字段添加了一个"s"字母。我更新了 post.

在这里,我尝试使用一种聚合操作的代码:

@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 字段的类型:String budgetCodes、String[] taskCodes 和 String[][] actionCodes。

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

有map结构的结果

这里是报表文件的类型String budgetCode, String[] taskCodes, String[][] actionCodes, List>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"
          ]
        ]
      }
    ]
  }
]

地图结构方法很有趣,但我在前端显示时遇到了一些问题,但这是另一个问题,因为键是对象类型。我会再次测试,然后我会告诉你。无论如何,这很有趣。事实上,我有另一个想法。我想要的是,在每个 JSON 文档中,我有一个 String 字段 budgetCodes,一个 String[] 字段 taskCodes,它将包含所有 taskCodes 链接到 budgetCodes,我认为最终真正适合我想要的是创建一个 TaskCode class 像这样:

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

    //Getters and Setters
}

通过这种方式,它将允许我为每个 JSON 文档提供一个带有 budgetCode 的简单字符串,一个带有 for 的链接任务代码列表 每个 taskCode 对象,String 属性 taskCode 将包含 taskCode 的值。最后每个 taskCode 对象将包含一个 String[] 与 actionCodes 列表。

关于POJO结构

它运行良好,但我在 AngularJS 前端显示数据时遇到了一些问题。我想做一个聚合操作来创建一个菜单,每次点击一个元素都会打开一个带有子列表的子菜单等等......我不知道聚合是否真的适应我想做的事。于是,我想到了另一种方法。除了进行聚合操作,也许另一种方法可以是通过简单的查找操作从数据库中检索我想要的数据,并使用服务层来执行树算法。

提前致谢

您可以在单个聚合管道中执行多级分组。

更新了现有项目阶段以包含 actionCode 并更新了现有组以包含 actionCode

这将显示展平结构,每行包含 budgetCodestaskCodesactionCodes

将您的 actionCodes 更新为 private 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;

这会将结果输出到 Map 中,为您提供多个分组。

类似

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"));