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 的所有内容 运行 保持不变。
所以在这一点上,我绝对是一个 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 的所有内容 运行 保持不变。