Firebase 数据库关系问题 - 为用户存储选定的项目

Firebase Database relationship issue - storing selected items for users

所以在这一点上,我绝对是一个 firebase,而且通常只是一个 noSql 菜鸟。这是我的问题。

我有一组这样的数据

-items
 --id1
   theData
 --id2
   theData
 --id3
   theData
 --id4
   theData      

我有一些用户会 select 此数据的一个子集。现在的示例用户 A 和用户 B。

-itemSelected
 ---UserA
    ---Id1  (different than item key)
       theData from items id1 (with items id1 key included so I can reference)
    ---Id2  (different than item key)
       theData from items id3 (with items id3 key included so I can  reference)
  ---UserB
    ---Id1 (different than item key)
       theData from items id1 (with items id1 key included so I can reference)
    ---Id2 (different than item key)
       theData from items id4 (with items id4 key included so I can reference)

有一个更规范化的结构 SQL 背景我觉得我正在做这个错误。在我开发过程中,我看到如果我更改项目数据的位置,那么我的用户数据文档中将包含错误数据。到目前为止,我在我的项目中并没有那么大的项目我想用 firebase 实时数据库完成它并且我喜欢让我的头脑围绕这个 noSql。那么我在应该如何设置方面遗漏了什么或做错了什么。或者我应该只切换到 Firestore,如果是的话,那如何解决我的问题。

仅供参考 - 我需要参考的原因是因为有时需要比较这 2 个数据,以便我可以正确显示 tables。我认为键是比较数据的自然方式。同样,我可能会非常 SQL 关注那里。

希望有一些 noSql 或 firebase 专家提供一些解决方案。谢谢!

更新

根据响应者 Bryan Massoth 的说法,我认为这是有目的的新结构。

-items
 --id1
   theData
 --id2
   theData
 --id3
   theData
 --id4
   theData      

我有用户将 select 此数据的一个子集,但不是存储数据的副本,只是存储项目 ID 的键值和 selected 的布尔值 true。示例用户 A 和用户 B。

-itemSelected
 ---UserA
    ---Id1  (different than item key)
       id1KeyFromItems: "True"
    ---Id2  (different than item key)
       id3KeyFromItems: "True"
  ---UserB
    ---Id1 (different than item key)
       id1KeyFromItems: "True"
    ---Id2 (different than item key)
       id4KeyFromItems: "True"

所以我看到的最后一个问题可能是我目前正在显示用户 selected 在另一个 table 中的数据,这就是为什么我最初写了所有 subselected数据到 userA 或 UserB 在 firebase 中的个人资料。所以我可以很容易地订阅它并从那里显示它。如果我走布尔路线,如果我只存储密钥,我怎么能只显示用户 A selected 的项目的数据?

很多结构取决于您将如何使用数据。我会说你的大部分结构都是正确的。我要做的唯一区别是不复制 itemSelected/{userId} 下的数据。如果选择了 itemId,只需将其设置为 true

-itemSelected
  -UserA
    -Id1 (same as items Id1): true
    -Id2 (same as items Id2): true

这会增加额外的负载,但可以通过良好的 UI/UX 设计隐藏这些负载。这将允许搜索选择了特定项目的用户。也能保证数据不坏

关于 "subset" 关于存储在 itemSelected 中的数据的评论:如果您指的是特定项目的数据是 [=15] 中为该项目存储的数据的子集=] table 并且是为安全而设计的(即 items 部分中的某些数据不应该被用户看到),那么我建议保持一切不变,只是创建一个 Firebase 函数来保持记录 "eventually" 一致。

所以我经历了这个。 Bryan 让我参与其中,所以我对他的回应投了赞成票,但我 post 在这里给出了完整的答案,这样其他人可能会受益。我试图尽可能地简化最初的问题,但我意识到这很困难,这可能不是最好的论坛,但我在其他任何地方都找不到答案,而且我有具体的用例,现在我可以分享更多代码。

用例总结。我将项目存储在 firebase 中。用户将从项目中转到 select。我需要存储它们 select 的内容,但要尽可能保持数据的可维护性。 Bryan 建议只存储密钥,这很好。但是我在 UI 中的 div 中显示了用户 selected 的内容,所以基本上如果我没有将数据存储在配置文件中,我将需要过滤原始项目数据(我在 bryan post) 之后根据我的用户配置文件中存储的密钥意识到了这一点。

我是一个 React 应用程序,所以我连接了 Reselect 并使用选择器加载了我与过滤器匹配的 2 个数据部分,并通过组件中的 redux 连接了它们。

如果您是 select 的新手,这个视频对我非常有帮助并让这个解决方案连接起来。

https://www.youtube.com/watch?v=XCQ0ZSr-a2o

相关代码select或此处。基本上,您获取项目列表和 userSelectedItems 列表(只是 keys/ids)并比较它们。如果它们相同,则过滤器将为新的过滤列表评估为真。

这是我的select之类的东西。

export function getUser(state) {
   return state.User;
 }

export function getUserItemsList(state) {
  return getTeam(state).list;
 }


export function getItemsList(state) {
 return state.Items.list
}

export function getUserItemsFilter(userItems, items) {

  const selectedItems = items.filter(
    item => userItems.some(userItem => userItem.itemKey === item.key));
   return selectedItems
 }

 export const ItemSelector = createSelector(
  getUserItemsList,  //pick off piece of state
  getItemsList,  //pick off piece of state
  getUserItemsFilter //last argument that runs for Item Selector, do processing here
 );

返回您导入的组件 select 或者您创建的组件,并将其连接到您的 mapStateToProps,就像这样。

 const mapStateToProps = state => {
  return {
   itemsSelected: ItemSelector(state),
   }
}


const mapDispatchToProps = Object.assign(
  {},
  userActions,
);

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(UserPage));

现在 ItemsSelected 将映射状态到您的 React 组件。它是过滤后的 Items 数组,仅包含与您存储在用户配置文件中的键具有相同键的值条目。

这确实解决了我原来的问题,即让我的数据更容易在 Firebase 中维护,因为所有数据都在项目中,而不是在用户配置文件中重复。感谢 React 中的 Immutable 和 Reselect。它们是为这些东西而建的。希望这可以帮助别人。一开始意识到这对于堆栈来说有点宽泛,希望代码有助于改进用例并使其现在对其他人有价值。

最后一次。我的数据现在在 firebase 中看起来像这样。

项目

-items
 --id1
   theData
 --id2
   theData
 --id3
   theData
 --id4
   theData      

用户资料

-itemSelected
 ---UserA
    ---Id1  (different than item key)
       "id": "id1KeyFromItems"
    ---Id2  (different than item key)
       "id": "id3KeyFromItems"
  ---UserB
    ---Id1 (different than item key)
       "id": "id1KeyFromItems"
    ---Id2 (different than item key)
       "id": "id4KeyFromItems"

我的高级数据库函数总是在 firebase 中创建新的唯一键。我不想仅仅为了这个解决方案而改变它。这有效并使我的应用程序中的 CRUD 的所有内容 运行 保持不变。