【问题标题】:Normalized many-to-many schema for client-side data store用于客户端数据存储的规范化多对多模式
【发布时间】:2017-07-18 03:18:03
【问题描述】:

我正在开发社交网络应用程序的浏览器前端。它有很多关系数据,具有 一对多 (1:m) 和大部分 多对多 (m:m) 关系,如下表所示。

我想在应用程序中使用 Flux 数据流架构。我将 Vuex.js 与 Vue.js 一起使用。

正如 Redux.js 文档中所述,最好为 various reasons 提供平坦、规范化的存储状态形状,以便与 React 一起使用,我认为与 Vue.js 一起使用也是如此。

  • 帖子有类别 (m:m)
  • 帖子有标签 (m:m)
  • 帖子有 cmets (1:m)
  • 帖子中包含主题标签 (m:m) // 或用户创建主题标签
  • 帖子中有提及 (m:m) // 或用户创建了用户提及

  • 用户喜欢帖子 (m:m)

  • 用户关注用户、帖子、帖子类别等 (m:m)
  • 用户最喜欢的帖子 (m:m)

等等

我将需要显示帖子提要及其所有其他实体的相关数据,例如用户、cmets、类别、标签。为此,就像有一个 1:many 关系,将这个关系的数据的 多方 保存在 one 方(可以说是parent),即使它实际上是 ma​​ny-to-many,对于通常查询它们来组成它们的父级(即 posts)似乎没问题.但是,我还需要反向查询商店状态,例如,获取具有特定 categorytagposts

在这种情况下,它并不像帖子那样容易。我需要一个 relation entity 来保存两个连接数据实体的 id 对,就像 join tableassociation table 在 RDBMS 中,为了便于访问和更新,避免深入挖掘状态,也避免不必要的重新渲染(该要求是 React 或 Vue.js 和 GUI 特定的)。

我怎样才能相对轻松有效地实现这一目标,例如就像 1:many 关系一样?

【问题讨论】:

  • 如果尝试这并不容易并且无效,也许可以使用 1:m 方式,但在 SPA 路由器中挂钩 on navigate像回调实现一个新的网络请求进入需要反向查询的视图的路由路径。结果可以合并到持有实体的对象中,该实体是这个 m:m 关系的第二个 many 边。
  • 您是否尝试过使用example 作为起点?您尝试过的一些代码将大大有助于回答您的问题。
  • 在我在上面发布这个问题之前,我刚刚浏览了这个例子。我认为这不是我问的情况的完全合适的事情。示例中的实体以及通常在有关此主题的示例中的实体是一对多相关的。从示例链接的输出中,我可以看到它包含每个实体中的相关实体引用。这并不意味着 m:m 关系。在这种关系中,m:m,我希望 join 键,例如 postToCategory,来保存 "postId": "categoryId" 的键值对。但是,您在示例中显示的方式也可以实现相同的效果。
  • 我想知道哪一个更容易实现和有效地用于客户端商店状态中的 m:m 关系,尤其是在 Flux 应用程序中,可能是 Redux 或 Vuex。在两个实体中保持关系,比如在posts.categoriescategories.posts 中类似于您的示例,或者有一个加入(关联)实体,比如postToCategory,并持有关键(对于帖子)值(对于类别)对,就像我在上面的评论中所说的那样在关系数据库系统中。

标签: redux vuex database-normalization normalizr


【解决方案1】:

根据您的最后评论。我将介绍我目前用于这种情况的数据结构:

标签

{
 "type": "tag",
 "id": "tag1",
 "name": "Tag One"
}

标记发布

{
  "id": "someId",
  "type": "postTag",
  "tagId": "tag1",
  "postId": "post1"
}

发帖

{
 "id": "post1",
 "name": "Post 1"
}

我发现存储关系 id 的 M:M 的每一方都可能产生孤儿。在双重位置管理这些 ID 会导致重复步骤并增加认知管理,因为管理 M:M 的所有功能都发生在两个地方而不是一个地方。另外,关系本身可能需要包含数据,这些数据会去哪里?

M:M 没有实体

{
 "id": "post1",
 "name": "Post 1"
 "tagIds": [
   {id: "tag1", extraAttribute: false} //this is awkward
 ] 
}

标签发布 - 附加属性

{
  "id": "someId",
  "extraAttribute": false,
  "postId": "post1"
  "type": "postTag",
  "tagId": "tag1",
}

还有一些额外的选项可以加快提取标签的速度。

发帖

{
 "id": "post1",
 "name": "Post 1"
 "tagIds" : ["tag1", "tag4"]
}

假设一个帖子的标签不会超过 20 个。使其成为通常可以忽略不计的存储要求以减少查找。我发现目前有 10000 个关系的数据库对此没有迫切需要。

易于访问和更新

1:M 是一个直接指向它想要的东西的对象。 M:M 是指向它们关系的两个不同实体。为这种关系建模,并集中逻辑

渲染

如果您的应用程序呈现很长的数据列表(数百或数千 行数),我们建议使用一种称为“加窗”的技术。这 技术在任何给定时间只呈现一小部分行, 并且可以显着减少重新渲染所需的时间 组件以及创建的 DOM 节点的数量。

https://reactjs.org/docs/optimizing-performance.html#virtualize-long-lists

我觉得解决方案可能是针对特定用例的,并且会受到更广泛的意见。我使用带有 Vuex 的沙发/袋子和一个包含 20,000 个条目的非常大的表遇到了这个问题。同样,在生产中,这些问题并不是非常明显。结果总是会有所不同。

我在这里尝试了几件事:

  • 加载部分数据集:文件内(非反应式)与内存中(在 Vuex 中加载)
  • 排序、分页、在文件中搜索和加载结果

【讨论】:

    猜你喜欢
    • 2018-03-24
    • 1970-01-01
    • 1970-01-01
    • 2013-01-22
    • 1970-01-01
    • 2012-07-01
    • 2013-06-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多