normalization - 如何使用 ngrx/entity(EntityState 和 EntityAdapter)规范化深度嵌套的数据

标签 normalization ngrx angular8 state-management ngrx-entity

我希望对来自我的服务器的数据进行规范化,以便我可以更轻松地与 ngrx/entity 一起使用它。

我喜欢ngrx/entity 如何通过提供EntityState 接口(interface)和EntityAdapter 来降低reducers 和其他东西的复杂性。但是我发现它不适用于嵌套数据。

我有 3 个级别的数据:

训练 -> 练习 -> 套装

如果我将它与经典的 ngrx/entity 模式一起使用,当我处理嵌套数据时,它会很快变得拥挤。

下面是我在使用 ngrx/entity 时遇到的第一件事
This is how data gets normalized when I put all trainings data in
在那之后,我四处窥探并进入了 normalizr 图书馆
Output
我喜欢 normalizr 如何规范化我的数据,也喜欢仅将 id 替换为嵌套数组值作为其他实体(练习、集)的键

我首先尝试的是组合多个实体状态,如下所示:
Entity states
但这需要改变我的服务器以及大量的逻辑和努力。

我想要以某种方式将 normalizr 与 ngrx/entity 结合起来。获得 normalizr 给我的同样的东西,但可以自由地使用来自ngrx/entity的实体适配器api,它是选择器和其他来自ngrx/entity为我服务的代码

所以底线我的问题是如何在没有某种服务器工作的情况下使用ngrx/entity(就像normalizr库一样)规范化深层嵌套数据。

最佳答案

所以我在仍然使用 NGRX 的同时找到了一些解决方法

在我开始之前,我只想说ngrx 也有提供更少样板的ngrx/data pack。但是,当我阅读它时,我找到了对我的问题的明确答案:

https://ngrx.io/guide/data/limitations
“这个库 浅克隆 集合中的实体数据。它 不会克隆复杂、嵌套或数组属性 。在询问 NgRx 数据之前,您必须进行深度相等测试和 克隆自己 保存数据。”

我相信这对于 ngrx/entity 也是如此。

我开始寻找替代解决方案:BreezeJs、NGXS、Akita,我发现 NGXS 对我来说很快就能理解,但需要努力将我的 ngrx 实现与项目分离。

所以我回到ngrx并尝试为3级深度嵌套数据做一个解决方法

创建 3 个独立的实体状态(我将尝试使用可以减少所有样板的 ngrx/data)

创建一个函数,该函数将为每个实体返回所有必要的实体和 ID(使用 normalizr 进行规范化)

export function normalizeTrainingArray(trainings: Training[]) {
var normalized = normalize(trainings, trainingsSchema);

var entities = {
    trainings: {},
    exercises: {},
    sets: {}
}
entities.trainings = normalized.entities.trainings ? normalized.entities.trainings : {};
entities.exercises = normalized.entities.exercises ? normalized.entities.exercises : {};
entities.sets = normalized.entities.sets ? normalized.entities.sets : {};

var ids = {
    trainingIds: [],
    exerciseIds: [],
    setIds: []
}
ids.trainingIds = normalized.entities.trainings ? Object.values(normalized.entities.trainings).map(x => x.id) : [];
ids.exerciseIds = normalized.entities.exercises ? Object.values(normalized.entities.exercises).map(x => x.id) : [];
ids.setIds = normalized.entities.sets ? Object.values(normalized.entities.sets).map(x => x.id) : [];

return {
    entities,
    ids
}

这样的事情就足够了。
发送 normalizeData Action 并使用效果来调用此方法并为 fetchedData 调度 3 个不同的 Action ...

类似于以下内容:
   trainingsNormalized$ = createEffect(() =>
    this.actions$.pipe(
        ofType(TrainingActions.normalizeTrainings),
        tap(payload => {

            var normalized = normalizeTrainingArray(payload.trainings);

            this.store.dispatch(TrainingActions.trainingsFetched({ entities: normalized.entities.trainings, ids: normalized.ids.trainingIds }))
            this.store.dispatch(ExerciseActions.exercisesFetched({ entities: normalized.entities.exercises, ids: normalized.ids.exerciseIds }))
            this.store.dispatch(SetActions.setsFetched({ entities: normalized.entities.sets, ids: normalized.ids.setIds }))
        })
    )
    , { dispatch: false });

在一个样本缩减器中:
    // GET ALL
on(TrainingActions.trainingsFetched, (state: TrainingState, payload: { entities: Dictionary<Training>, ids: string[] }) => {
    return {
        ...state,
        entities: payload.entities,
        ids: payload.ids
    }
}),

结果是:

result

关于normalization - 如何使用 ngrx/entity(EntityState 和 EntityAdapter)规范化深度嵌套的数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57856095/

相关文章:

python - 使用二进制和连续变量标准化数据以进行机器学习

angular - 防止 NGRX 效应产生的冗余 API 调用

angular - 如何保存搜索查询并将其显示在新组件上?

新 loadChildren 导入语法中的 Angular 8 延迟加载模块未被延迟加载

angular - 使用 Angular 7 在 swiper 中导航不起作用

数据库:表是否应该始终规范化并具有主键?

过滤/归一化不良信号的算法

PostgreSQL - 使用 AVG、MAX 和 MIN 进行规范化

angular - ngrx 组件存储效果在 promise 错误后不会触发

angular - 这个 ngrx 选择器在做什么?