如何在NoSQL环境中创建以下数据结构
如何在NoSQL环境中创建以下数据结构
简介
我有一个类似社交媒体数据库的FireStore数据库,包括3个集合:Users(用户)、Events(事件)和EventUpdates(事件更新)。我的目标是创建一个由我和我的朋友创建的事件更新的动态。所以我需要扩展我的数据库以建立友谊连接。但我遇到了3个问题,希望这里的某个人能指导我解决这些问题。
问题/疑问1:
我在EventUpdate模型中添加了用户名和用户图像,以便更容易进行查询。我听说在NoSQL数据库中去规范化是一个好方法。但是,如果用户更新了用户图像,我必须更新该用户创建的所有事件更新。听起来不是一个好的做法。但是否有更好的方法来解决这个问题?
问题/疑问2:
我该如何创建一个针对以下查询进行优化的数据结构:按日期获取我和我的朋友的事件更新。
问题/疑问3:
如何存储点赞信息?我可以在一个eventUpdate中保留一个计数器。但是,当我对eventUpdates进行去规范化时(参见下面的当前解决方案),这会成为一个问题。
数据结构示例。
{
"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副本的更新。对我来说,Firebase似乎不适合我的项目,我正在考虑用SQL数据库替换它,或者这里有人可以用更好的解决方案改变我的想法吗?
{
"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"
}
}
}
如何在NoSQL环境中创建以下数据结构的原因和解决方法
当我们在NoSQL数据库中添加用户名和用户图像到EventUpdate模型时,这样可以更容易查询。我听说在NoSQL数据库中,反规范化是一种常见的做法。
反规范化是指将数据冗余存储在多个地方,这样可以提高查询效率。在Firebase中也采用了这种做法。如果你对NoSQL数据库不熟悉,我建议你观看这个视频《Denormalization is normal with the Firebase Database》,以便更好地理解。虽然这个视频是关于Firebase实时数据库的,但是同样的规则也适用于Cloud Firestore。
但是,如果用户更新了用户图像,那么我需要更新该用户创建的所有eventUpdates。听起来这是一件比较麻烦的事情。但是,有没有更好的方法来解决这个问题呢?
是的,你说得对。你需要更新所有包含该图像的位置。因为你选择了google-cloud-firestore作为标签,所以我建议你查看我在这个帖子中的回答,因为在写入操作较多的情况下,Firestore可能会有点昂贵。请参阅Firestore的定价计划。
关于Firestore,你可以只存储一个图片的引用,而不是整个对象。在这种情况下,你不需要做任何更新操作。这两种技术之间总是一个权衡的问题,不幸的是没有中间的方法。你要么存储对象,要么只存储对象的引用。关于这个问题,请参阅我在这个帖子中的回答。
如何创建一个在NoSQL环境中用于执行以下查询的数据结构:按日期排序获取我和我的朋友的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"类型。请参阅我在这个帖子中的回答,以了解如何在Cloud Firestore数据库中添加日期属性。
如何存储"likes"?你可以简单地添加"likes",但是我建议你参考我在这个帖子中的回答的最后部分。所以,你可以考虑将计数器添加到Firebase实时数据库而不是Cloud Firestore中。这两个数据库可以很好地协同工作。
这个结构似乎可行,但是我对这个解决方案的问题是,为了更新单个eventUpdate,我需要进行大量的写入调用,因为每个feed中都有很多副本(1000个关注者意味着1000个副本)。而且看起来我需要经常这样做。
你也可以看一下我在这个帖子中的回答。
对于我来说,Firebase并不适合我的项目,我在考虑将其替换为SQL数据库,或者有人能够提供更好的解决方案吗?
我不认为是这样的。有很多应用程序与你的机制完全相同,并且运行得非常好。
嗨,Luciano!我可以帮你提供其他信息吗?
谢谢,这些信息非常有帮助。我已经有了一些关于如何重构我的结构的想法,但是还需要实施并观察其性能。
不客气,Luciano!如果你有任何其他问题,只需发布另一个问题,我或其他Firebase开发者都可以帮助你。祝你好运!
在NoSQL环境中如何创建以下数据结构的问题出现的原因是Firestore对NoSQL世界有不同的方法。一旦您知道将要使用的数据(正如您已经知道的)后,关于数据将具有什么结构有一些非常重要的要点。这非常取决于数据的增长方式、您将需要什么样的查询以及您将多频繁地使用它们。某些情况下,您可以创建一个根集合来聚合数据,这样查询可能会更容易。
解决方法是参考Firebase频道的一段很好的视频。以下是视频链接:
How to Structure Your Data | Get to Know Cloud Firestore #5
https://www.youtube.com/watch?v=haMOUb3KVSo
更新于12月26日的其他视频也可以帮助您对数据进行建模和查询:
How to Connect Firebase Users to their Data - 3 Methods
https://www.youtube.com/watch?v=jm66TSlVtcc
How to NOT get a 30K Firebase Bill
https://www.youtube.com/watch?v=Lb-Pnytoi-8
Model Relational Data in Firestore NoSQL
https://www.youtube.com/watch?v=jm66TSlVtcc
在NoSQL环境中创建上述数据结构的问题源自于需要将动态更新与真实用户数据同步(例如,当用户更改个人资料图片时)。解决方法是将用户ID存储在eventUpdate
文档中。这样,就不需要手动保持它们的同步,每次在动态中显示条目时,只需获取用户数据,并根据userId
和created_at
字段轻松查询多个eventUpdate
。
要在动态中实现点赞功能,解决方案取决于一系列因素,如流量量。
最简单的方法是使用事务更新likes
字段,但Firestore对单个文档的最大更新频率为1秒。此外,如果有超过5个事务试图更新同一文档,事务很容易失败。
要实现更可靠的likes
系统,请参考官方Firebase文档中的此页面。