过滤嵌套的可观察数组 RxJs Angular

Filter nested observable array RxJs Angular

我正在尝试使用 RxJs 库的组合管道函数中的过滤器函数过滤 angular 中的一些可观察嵌套数组。

问题: 我只想显示具有特定日期给出的调查的类别。

简化情况: 我的 angular 组件有 3 个单选按钮(值 1、2、3)。如果我点击其中之一,它会转到我的 'FilterChanged($event.value)' 函数。在此函数中,我想过滤 api 提供的数据。这个api 首先提供了所有的类别。检索数据后,我想根据单选按钮进行过滤。

这是我从 api:

得到的数据
[
  {
    "category": "A",
    "surveys": [
      {
        "day": "1",
        "answers": [
          {
            "name": "1",
            "value": "a"
          },
          {
            "name": "2",
            "value": "b"
          },
          {
            "name": "3",
            "value": "c"
          }
        ]
      },
      {
        "day": "2",
        "answers": [
          {
            "name": "1",
            "value": "a"
          },
          {
            "name": "2",
            "value": "b"
          },
          {
            "name": "3",
            "value": "c"
          }
        ]
      },
      {
        "day": "3",
        "answers": [
          {
            "name": "1",
            "value": "a"
          },
          {
            "name": "2",
            "value": "b"
          },
          {
            "name": "3",
            "value": "c"
          }
        ]
      }
    ]
  },
    {
    "category": "B",
    "surveys": [
      {
        "day": "2",
        "answers": [
          {
            "name": "1",
            "value": "a"
          },
          {
            "name": "2",
            "value": "b"
          },
          {
            "name": "3",
            "value": "c"
          }
        ]
      },
      {
               "answers": [
          {
            "name": "1",
            "value": "a"
          },
          {
            "name": "2",
            "value": "b"
          },
          {
            "name": "3",
            "value": "c"
          }
        ]
      },
      {
        "day": "2",
        "answers": [
          {
            "name": "1",
            "value": "a"
          },
          {
            "name": "2",
            "value": "b"
          },
          {
            "name": "3",
            "value": "c"
          }
        ]
      }
    ]
  }
]

如果选择单选按钮 1,我想只显示类别 A 并且只显示它有 1 个调查,因为这是唯一符合过滤器的调查。

为什么这段代码不起作用??更新过滤器在单选框更改事件中被触发。对我来说,这比 reduce with spreader 函数更具可读性。

  updateFilter(filterDays : number): void {
    var filterDate = this.getFilterDate(filterDays);
    this.surveyTypes$ = this.allSurveyTypes$.pipe(map((types) => this.filterSurveyTypes(types, filterDate)));
  }

  filterSurveyTypes(types : SurveyType[], filterDate : Date) : SurveyType[] {
    return types.filter(type => type.surveys.filter(survey => moment(survey.filledInDate).isSameOrAfter(filterDate)).length);
  }

还有很多变体,但它似乎不起作用。 我想我不需要地图,因为我没有转换任何数据,所以过滤器应该没问题,但到目前为止对我不起作用。

感谢您的帮助。谢谢

这也适合你:

let teste = [];
allcategories.forEach( category => { 
    category.surveys.forEach( survey => {
        if (survey.day == '1'){
            teste.push(survey)
        }
    })
})

这取决于您如何使用 observable,这里有 2 个示例:

  • 如果你想在 属性 中设置类别,而不是可观察的,你必须使用这样的订阅方法:
this.subscription = this.categories$.subscribe({
  next: categories => this.categories = categories
});

然后使用this.categories。在这种情况下,不要忘记在销毁组件时调用此 subscription.unsubscribe()。

  • 如果您在带有异步管道的组件模板中使用它,它应该可以正常工作。

Remark: an observable is not activated if there is no subscribe (the async pipe does the subscribe and unsubscribe)

我在这里看到的问题是:过滤器函数不同步。这意味着,当您调用第二个过滤器时,第一个过滤器会得到 Promise-like 响应。由于您的代码不是异步的,过滤器将响应所有元素,或 none.

要解决这个问题,您必须将函数声明为异步函数。

以下是有关如何执行此操作的一些示例:

async function awesomeFilter(allcategories){
    return await allcategories.filter(category =>
        category.surveys.filter(survey => survey.day == '1').length 
    )
}

survey.day 将是您的嵌套验证;

.length 将 return 到第一个过滤器 0 如果没有找到对应关系或 positive value 如果有,则告诉第一个过滤器对应关系在哪里。

这样我就可以让它工作了。希望对你有所帮助。

不确定您要查找的内容,但似乎您想根据内部数组中的内容过滤外部数组并过滤内部数组,这可以通过 [=12 一次完成=]:

function filterOuterByInner(array, value) {
  return array.reduce((acc, v) => {
    const tmp = { ...v }; // create shallow copy
    tmp.surveys = tmp.surveys.filter(a => a.day === value); // filter surveys array by value
    if (tmp.surveys.length)
      acc.push(tmp); // add to acc array if any surveys after filter
    return acc;
  }, []);
}

然后在您的地图中使用它:

this.categories$ = combineLatest(this.allcategories$, this.value$).pipe(map(([categories, val]) => filterOuterByInner(categories, val)));