rxjs / ngrx / groupby嵌套值

时间:2017-10-23 15:15:31

标签: javascript rxjs ngrx

我几天都在苦苦挣扎,可能需要一些更高级的人的帮助:)。

problem

正如您在我的照片中看到的,我得到了以下结构。

我在Observable中有n个任务:

  • 任务[]
    • [0]任务ID 1
      • [0]工作[]
        • [0]工作1
          • ...
        • [2]工作3
          • job id 3
          • ...
          • 参考ID 515

我想做什么?

我想通过引用ID对我的所有任务进行分组,这样我就可以通过离子从html访问我的Observable。

private getTasksWithReference()
{
let localTasksWithReference = this._store.select(state => state.tasks)
  .map((localTasks: Task[]) => 
  {
    return localTasks.filter((localTask: Task) =>
    {
      return this.typeCode.toString() === 
 localTask.taskProcessTypeCode.toString();
    })
  });

let test = localTasksWithReference.switchMap(tasks => Observable.from(tasks)
  .groupBy(task => task.taskType)
  .mergeMap(group => group.toArray())
  .toArray()
);

let test2 = localTasksWithReference.switchMap(tasks => tasks.map(task => 
Observable.from(task.jobs)
  .groupBy(job => job.businessTransactionDocumentReference.id)
  .mergeMap(group => group.toArray())
  .toArray()
));

Test2是我想要实现的,但它并没有给我预期的结果。即使我需要保留上面发布的结构而不仅仅是工作。

如果有人可以提供帮助,那将是一个很大的帮助:)

此致 NOSTA

3 个答案:

答案 0 :(得分:0)

这是我认为你需要的基础

const grouped$ = localTasksWithReference$.reduce( (grouping, task) => {

  // Get all referenceIds for the task
  const referenceIds = task.jobs.reduce( (references, job) => { 
    references.push(job.referenceId);
    return references;
  }, []);

  // Add each referenceId and task to the grouping 
  referenceIds.forEach(referenceId => {
    grouping[referenceId] = grouping[referenceId] || [];
    // Ensure task only grouped once per referenceId
    if (grouping[referenceId].indexOf(task) === -1) {
      grouping[referenceId].push(task);
    }
  })

  return grouping;
}, {});

您可以在此处查看其工作并进行调整CodePen

输出是一个对象的可观察对象,该对象具有每个不同referenceId的属性,属性值是具有该referenceId的作业的任务数组。

{
  ref#1: [
      {taskId: 1, jobs: Array(3)}
      {taskId: 2, jobs: Array(3)}
    ],
  ref#2: [
      {taskId: 1, jobs: Array(3)}
      {taskId: 2, jobs: Array(3)}
    ]
}

您需要对此输出进行整形以在模板上正确使用。如果您需要帮助,请显示建议的HTML结构。

注意,我假设每个referenceId只能出现一次任务。

答案 1 :(得分:0)

谢谢@Richard Matsen。

let localTasksWithReference = this._store.select(state => state.tasks)
        .map((localTasks: Task[]) => {
            return localTasks.filter((localTask: Task) => {
                return this.typeCode.toString() === localTask.taskProcessTypeCode.toString();
            })
        });

    let referenceGroup = localTasksWithReference.reduce((grouping, tasks: any) => {
        tasks.reduce((test, task) => {
            let referenceIds =
                task.jobs.reduce((references, job) => {
                    references.push(job.businessTransactionDocumentReference.id);
                    return references;
                }, []);

            referenceIds.forEach(referenceId => {
                grouping[referenceId] = grouping[referenceId] || [];
                if (grouping[referenceId].indexOf(task) === -1) {
                    grouping[referenceId].push(task);
                }
            })
        }, []);
        console.log(grouping);
        return grouping;
    }, {});

this.tasksWithReference = referenceGroup;
this.tasksWithReference.subscribe(console.log);

Result

像魅力一样工作。但我确实需要一些HTML帮助。

我想要做的是referenceId作为标题和下面的任务。

<ion-card>
  <ion-list>
    <ion-list-header *ngFor="let taskWithReference of tasksWithReference | async">
      test
    </ion-list-header>
  </ion-list>
</ion-card>

我想我们需要一个不是对象的数组吗?我在这里与离子合作。

这是我的工作任务的样子,以及我的分组参考。

references

答案 2 :(得分:0)

如果有人有兴趣,有两种方法可以解决这个问题:

private getTasksWithReferenceOOOOOOOOLD() {
    let localTasksWithReference = this._store.select(state => state.tasks)
        .map((localTasks: Task[]) => {
            return localTasks.filter((localTask: Task) => {
                return this.typeCode.toString() === localTask.taskProcessTypeCode.toString();
            })
        }).reduce((grouping, tasks: any) => {
            grouping = {};
            tasks.reduce((test, task) => {
                let referenceIds =
                    task.jobs.reduce((references, job) => {
                        references.push(job.businessTransactionDocumentReference.id);
                        return references;
                    }, []);


                referenceIds.forEach(referenceId => {
                    grouping[referenceId] = grouping[referenceId] || { "tasks": [] };
                    if (grouping[referenceId].tasks.indexOf(task) === -1) {
                        grouping[referenceId].tasks.push(task);
                    }
                })
            }, []);
            const arr = Object.keys(grouping).reduce((arr, key) =>
                ([...arr, { ...grouping[key], key }]), // Can add key if you don't have it
                []);
            this.tasksWithReference = Observable.of(arr);
            return arr;
        }, {}).subscribe();
}

现在我可以使用reference.tasks来访问带有键和任务的referenceid。

第二个解决方案:

public tasksWithReferenceMap: Map<string, Task[]>

public getTasksWithReference() {
    this.tasksWithReference = this._store.select(state => state.tasks)
        .map((localTasks: Task[]) => {
            this.tasksWithReferenceMap = new Map<string, Task[]>();
            return localTasks.filter((localTask: Task) => {
                return this.typeCode.toString() === localTask.taskProcessTypeCode.toString();
            }).reduce((grouping, task: Task) => {
                // Get all referenceIds for the task
                const referenceIds = task.jobs.reduce((references, job: Job) => {
                    references.push(job.businessTransactionDocumentReference.id);
                    return references;
                }, []);

                // Add each referenceId and task to the grouping 
                referenceIds.forEach(referenceId => {
                    grouping.set(referenceId, grouping.get(referenceId) || []);
                    if (grouping.get(referenceId).indexOf(task) === -1) {
                        grouping.get(referenceId).push(task);
                    }
                })

                return grouping;
            }, this.tasksWithReferenceMap);
        });
}

在这里使用地图。

我们必须创建一个自定义管道:

import { Task } from './../../models/task.model';
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
 name: 'keys',
 })
 @Pipe({ name: 'keys' })
 export class KeysPipe implements PipeTransform
 {


 transform(value: Map<string, Task[]>, args: string[]): any
  {
    let keys = [];
    for (let key of value.keys())
    {
      keys.push({ key: key });
    }
    return keys;
  }
}

并访问html:

 <ion-list *ngFor="let reference of tasksWithReference | async | keys | orderBy: 'key' : reverseReference">
        <ion-list-header class="referenceListHeader">
          {{'REFERENCE' | translate}}: {{reference?.key}}
        </ion-list-header>
        <ion-item-sliding *ngFor="let task of tasksWithReferenceMap.get(reference?.key) | orderBy: 'id'; let i = index">

再次感谢您的帮助,否则会花费更多时间;)