如何在 NoSQL 环境中创建以下数据结构

Posted

技术标签:

【中文标题】如何在 NoSQL 环境中创建以下数据结构【英文标题】:How to create the following data structure in a NoSQL environment 【发布时间】:2019-02-25 23:08:11 【问题描述】:

简介 我有一个类似于社交媒体数据库的 FireStore 数据库,其中包含 3 个集合用户、事件和事件更新。我的目标是使用我和我的朋友创建的 eventUpdates 创建一个提要。所以我必须用友谊连接来扩展我的数据库。但是我在 3 个问题上苦苦挣扎,希望这里有人可以推动我朝着正确的方向解决这些问题。

问题/问题 1: 我在 EventUpdate 模型中添加了用户名和用户图像,以便于查询。我听说非规范化是进入 NoSQL 数据库的方式。但是如果用户更新他的用户图像,我必须更新该用户创建的所有 eventUpdates。听起来像是你不想做的事情。但是有没有更好的方法来做到这一点?

问题/问题 2: 如何创建针对执行以下查询而优化的数据结构:从我和我的朋友那里获取 eventUpdates,按日期排序。

问题/问题 3: 如何存储喜欢?我可以在 eventUpdate 中保留一个计数器。但是,当我对 eventUpdates 进行非规范化时,这会成为一个问题(请参阅 EDIT 下面的当前解决方案)..

数据结构示例 .


  "users": 
    "1":  "name": "Jack", "imageUrl": "http://lorempixel.nl" 
  ,
  "events": 
    "A":  
      "name": "BeerFestival", 
      "date": "2018/09/05",
      "creatorId": "1"
    
  ,
  "eventUpdates": 
    "1": 
      "timestamp": "13243543",
      "creatorId: "1",
      "creatorName": "Jack",
      "creatorImageUrl": "http://lorempixel.nl",
      "eventId": "A",
      "message": "Lorem ipsum"
    
  

编辑

好的,经过反复试验,我最终得到了以下结构。这种结构似乎可行,但我对这个解决方案的问题是,由于每个提要中的所有副本(1000 个关注者意味着 1000 个副本),我需要进行大量写入调用来更新单个 eventUpdate。看起来我需要做很多事情。

例如,我想为每个事件更新添加一个赞按钮。这会触发所有 EventUpdate 副本的更新。对我来说,firebase 似乎不适合我的项目,我正在考虑用 SQL DB 替换它,或者这里的任何人都可以用更好的解决方案改变我的想法吗?


  "users": 
    "user1":  "name": "Jack", 
      "imageUrl": "http://lorempixel.nl",
      "followers": ["user1"]
    
  ,
  "feeds": 
    "user1": 
      "eventUpdates": 
        "1": 
          "timestamp": "13243543",
          "creatorId: "1",
          "eventId": "A",
          "message": "Lorem ipsum"
        
      ,
      "following": 
        "user1":  
          "name": "Jack", 
          "imageUrl": "http://lorempixel.nl",
          "followers": ["user1"]
        
      
  ,
  "events": 
    "A":  
      "name": "BeerFestival", 
      "date": "2018/09/05",
      "creatorId": "1"
    
  

【问题讨论】:

在 Firestore 中,您可以使用参考作为字段值。当你进行非规范化时,使用引用来指向可以改变的事物。如果它不能或不应该改变,那么使用一个值。接下来,您需要异步加载您的消息。首先,检索消息列表,然后解析引用。根据您使用的技术,有许多选项,但基本上只是运行第二个查询。 Firestore 将在设备上缓存结果,因此对同一文档的后续查询只会返回缓存。 【参考方案1】:

我在 EventUpdate 模型中添加了用户名和用户图像,以便于查询。我听说非规范化是在 NoSQL 数据库中使用的方法。

没错,denormalization,这是 Firebase 的常见做法。如果您是 NoQSL 数据库的新手,我建议您观看此视频,Denormalization is normal with the Firebase Database 以便更好地理解。它适用于 Firebase 实时数据库,但同样的规则适用于 Cloud Firestore。

但是如果用户更新他的用户图像,我必须更新该用户创建的所有 eventUpdates。听起来像是你不想做的事情。但是有没有更好的方法来做到这一点?

是的,这也是正确的。您需要更新该图像存在的所有位置。因为您选择了google-cloud-firestore 作为标签,我建议您从这个post 中查看我的答案,因为在许多写入操作的情况下,Firestore 可能会有点贵。另请参阅Firestore pricing plans。

关于 Firestore,您只能保存对图片的引用,而不是保存整个对象。在这种情况下,您无需更新任何内容。这始终是这两种技术之间的交易,不幸的是,两者之间没有办法。您要么持有对象,要么只持有对对象的引用。为此,请参阅我的回答 post

如何创建一个为执行以下查询而优化的数据结构:从我和我的朋友那里获取按日期排序的 eventUpdates。

正如我所见,您的架构更像是 Firebase 实时数据库架构,而不是 Cloud Firestore。为了回答您的问题,是的,您可以创建。所以说到 Firestore,你可以创建一个名为 eventUpdates 的集合,它可以保存 eventUpdate 对象并根据时间戳查询它,需要这样的查询:

FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
CollectionReference eventUpdatesRef = rootRef.collection("eventUpdates");
Query query = eventUpdatesRef.orderBy("timestamp", Query.Direction.ASCENDING);

但请注意timestamp 字段的类型应为Date 而不是long。另请查看我对此 post 的回答,了解如何在 Cloud Firestore 数据库中添加日期属性。

如何存储喜欢?我可以在 eventUpdate 中保留一个计数器。但是,当我对 eventUpdates 进行非规范化时,这会成为一个问题(请参阅 EDIT 下的当前解决方案)

您可以简单地添加喜欢,但我建议您从这个 post 中查看我的回答的最后一部分。因此,您可以考虑将该计数添加到 Firebase 实时数据库而不是 Cloud Firestore 中。两个数据库一起工作得很好。

这种结构似乎可行,但我对这个解决方案的问题是,由于每个提要中的所有副本(1000 个关注者意味着 1000 个副本),我需要进行大量写入调用来更新单个 eventUpdate。看来我需要做很多事情。

你也可以看看我在这个 post 的回答。

对我来说,firebase 似乎不适合我的项目,我正在考虑用 SQL DB 替换它,或者这里的任何人都可以用更好的解决方案改变我的想法吗?

我不这么认为。有许多应用程序与您的机制完全相同,并且运行良好。

【讨论】:

嗨卢西亚诺!我可以帮助您了解其他信息吗? 谢谢,很多有用的信息。我已经想到了如何重构我的结构,但仍然需要实现它并查看它的性能。 不客气,卢西亚诺!如果您还有其他问题,请发布另一个问题,以便我或其他 Firebase 开发人员可以帮助您。干杯!【参考方案2】:

如果您希望您的提要项目与真实用户数据同步(例如,用户更改后的新个人资料图片),您只需将用户 ID 存储在 eventUpdate 文档中即可。这样您就不必手动使它们保持同步,并且每次必须在提要中显示项目时,您都可以简单地获取用户数据,并轻松查询 userIdcreated_at 字段上的许多 eventUpdates (假设你有它们)。

要在您的 Feed 中实现点赞,解决方案取决于流量等一系列因素。 最简单的方法是使用事务更新 likes 字段,但 Firestore 对单个文档的最大更新频率为 1 秒。此外,如果超过 5 个事务尝试更新同一个文档,则事务很容易失败。

要实现更可靠的 likes 系统,请查看 Firebase 官方文档中的 this page。

【讨论】:

【参考方案3】:

Firestore 对 NoSQL 世界采用了不同的方法。一旦你知道了你将使用的数据(就像你已经做过的那样),关于数据将具有什么架构,有一些非常重要的点。这在很大程度上取决于数据的增长方式、您需要什么样的查询以及使用它们的频率。在某些情况下,您可以创建一个聚合数据的根集合,这样查询可能会更容易。

Firebase 频道有一段很棒的视频可能会有所帮助。看看这个! 如何构建您的数据 |了解 Cloud Firestore #5 https://www.youtube.com/watch?v=haMOUb3KVSo

[更新]12 月 26 日

其他可能有助于建模和查询数据的视频是这些视频:

如何将 Firebase 用户连接到他们的数据 - 3 种方法 https://www.youtube.com/watch?v=jm66TSlVtcc

如何不获得 30K Firebase 账单 https://www.youtube.com/watch?v=Lb-Pnytoi-8

在 Firestore NoSQL 中为关系数据建模 https://www.youtube.com/watch?v=jm66TSlVtcc

【讨论】:

以上是关于如何在 NoSQL 环境中创建以下数据结构的主要内容,如果未能解决你的问题,请参考以下文章

如何在 mongodb atlas 中创建插入触发器?

如何在 SwiftUI 中创建核心数据管理器环境

如何在 Azure 环境中创建 DSN?

在 conda 中创建环境时如何修复错误

由 Terraform 在 LocalStack 中创建的 DynamoDB 表在 NoSQL Workbench 中不可见

如何在实体框架数据库迁移中创建全文目录? [复制]