【问题标题】:Stuck on designing the schema for my firebase database坚持为我的 firebase 数据库设计架构
【发布时间】:2014-08-15 00:06:41
【问题描述】:

我来自 SQL 背景,因此在设计我的 NoSQL firebase 架构时遇到了问题。我习惯于使用“WHERE”子句查询任何内容,而在 firebase 中这样做似乎更困难(尽管性能很容易弥补它!)。

我正在为歌曲存储“轨道”对象。这些对象具有以下键/值对,例如艺术家名称、曲目标题、流派、评分、创建日期等:

tracks
|_____-JPl1zwOzjqoM8xDTFll
          |____ artist: "Bob"
          |____ title: "so long"
          |____ genre: "pop"
          |____ rating: 52
          |____ created: 1403129692781
|
|_____ -JPv7KnVi8ASQJjRDpvh
          |____ artist: "Mary"
          |____ title: "im alright now"
          |____ genre: "rock"
          |____ rating: 70
          |____ created: 1403129692787

我网站上的默认行为是列出所有这些曲目,最新添加的曲目显示在列表顶部。我可以将我的 $priority 设置为要创建,然后将其变为负数(已创建 * -1)以实现我相信的效果。

但将来,我希望能够通过其他方式过滤/查询列表,例如:

  • 检索所有具有摇滚、流行或嘻哈流派的曲目。

  • 检索评分为 80 或更高且在过去 7 天内添加的所有曲目。

如何在 firebase 中实现这一点?我的理解是,实际上只有 2 种方式来订购数据:

  1. 通过“ID”值,它的物理位置为“firebaseURL.firebaseio.com/tracks/id”,在我的例子中,它是在我添加曲目时自动为我选择的。这没关系(我认为),因为我有用于列出详细信息的各个跟踪页面的页面,并且我网站上的 URL 类似于“www.mysite.com/tracks/-JPl1zwOzjqoM8xDTFll”。

  2. 通过使用 $priority,在我的例子中,我使用了“created”值,以便按正确的日期顺序排列我的列表。

考虑到我的设置方式(如果有更好的方法,请告诉我),有没有一种方法可以让我轻松查询特定类型或特定评级?

我阅读了博客“非规范化您的数据是正常的”(https://www.firebase.com/blog/2013-04-12-denormalizing-is-normal.html),我想我明白了。根据 Anant 的描述,实现我想要的一种方法可能是在 firebase 中为一个流派创建一个新对象并列出那里的所有曲目,如下所示:

tracks
|______ All
        |_____ -JPlB34tJfAJT0rFT0qI
        |_____ -JPlB32222222222T0qI
        |_____ -JPlB34wefwefFT0qI

|______ Rock
        |_____ -JPlB32222222222T0qI
        |_____ -JPlB34tJfAJT0rFT0qI

|______ Pop
        |_____ -JPlB34wefwefFT0qI

博客的前提是硬盘空间便宜,但用户的时间却不便宜。因此,存在重复数据是可以的,因为它允许更快的读取。

这是有道理的,我不介意这种方法。但这只有在用户只想从一种流派中选择所有曲目时才有效。如果他们想从摇滚和流行音乐中获取所有曲目怎么办?每次有人提交任一类型的歌曲时,我是否必须存储另一个名为 Rock&Pop 的对象并在其中存储一首曲目?

genre
|_______pop-rock
         |_________ -JPlB34tJfAJT0rFT0qI (a rock song)
         |_________ -JPlB34wefwefFT0qI (a pop song)
         |_________ -JPlB32222222222T0qI (a rock song)

另外,存储整个轨道对象或仅使用 trackid 的引用是否更有意义?例如,在 /genre/pop 下:

Should I store just the reference?
genre
|______ pop
        |______ -JPlB34wefwefFT0qI

Or, Should I store the entire track?
genre
|______ pop
        |______ -JPlB34wefwefFT0qI
                    |___ artist: "bob"
                    |___ title: "hello"
                    |___ genre: pop
                    |___ etc..

这两种方法有性能差异吗?我在想也许后者会更快,因为我不需要查询每个单独的曲目以获取其他详细信息,但我只是想确定一下。

我已经多次重做我的 firebase 架构。我做了一些改进,但是随着我的应用程序变得越来越大,更改它变得更加昂贵并且消耗更多时间。如果我能在我花大量时间重做其余代码以再次匹配之前最后一次解决这些问题,那就太好了..

感谢您对此的任何帮助,非常感谢。如果您需要更多信息,请告诉我。

【问题讨论】:

    标签: firebase firebase-realtime-database


    【解决方案1】:

    在上面的示例中,您构建了不同的层次结构并存储了一些数据,但只需将 ID 作为键放入。所以当你把它放到客户端上时,你可能最终还是会按一些数据字段进行排序。

    我喜欢让 Firebase 使用多部分键为我处理排序。

    例如,如果我需要按流派和艺术家姓名访问曲目,我会创建一个名为 trackByGenreAndArtist 的平面索引节点,其键由流派名称 + 艺术家名称 + 轨道名称 + 轨道 ID 组成。该值将是一个具有艺术家姓名、艺术家 ID、曲目名称和曲目 ID 的对象。添加 id 只是为了确保它是唯一的。

    现在可以按照流派、艺术家和曲目名称的顺序访问所有数据。你甚至可以对它进行预测搜索,它是如此之快。

    假设用户选择了“摇滚”流派,她在搜索框中输入了“B”。您可以通过抓取名称以“B”开头的艺术家的前十首曲目来填充预测下拉列表:

    indexRef.orderByKey().startAt('Rock'+'B').limitToFirst(10);
    

    使用您存储在该位置的部分数据对象在下拉列表中显示艺术家的姓名和曲目。

    如果用户选择预测,则使用轨道 ID 从您的轨道节点检索完整的轨道对象,并使用艺术家 ID 从艺术家节点检索完整的艺术家对象。

    如果用户输入了不同的字母,那么只需抛开你的预测并进行另一个预测提取,例如,

    indexRef.orderByKey().startAt('Rock'+'Br').limitToFirst(10);

    另外,如果您需要同时搜索摇滚和流行音乐流派该怎么办?好吧,您可以非常快速地执行上述两个查询

    indexRef.orderByKey().startAt('Rock'+'Br').limitToFirst(10);

    indexRef.orderByKey().startAt('Pop'+'Br').limitToFirst(10);

    您可以在预测下拉菜单中将它们分别分组:前十个来自 Rock,然后是前十个来自流行音乐。如果这对您来说还不够高效,我想您总是可以使用相同的微小数据对象和可以选择作为搜索过滤器的每个独特的流派组合来制作大量组合索引。不过,“磁盘很便宜,但用户的时间不便宜”是您的指导格言。

    【讨论】:

      【解决方案2】:

      Firebase 将在明年为查询 API 推出大量新增功能。上下文搜索(像 bar 这样的 foo)可能永远不会在实时数据中大受欢迎——它既慢又麻烦。

      有一篇关于 Firebase 中的 sql 查询和等效模式的两部分博客文章。我会推荐你​​give it a read-through。第 2 部分特别讨论了Flashlight

      为什么选择 ElasticSearch 和服务?与实时数据存储和同步一样,搜索是一个复杂的主题,具有大量样板和可发现的复杂性。在 SQL 中编写 where 子句很容易,这会给你带来一些方法,但它很快就达不到用户的期望。

      ES 可以快速与 Firebase 集成(我上次尝试时,Flashlight 服务与应用集成不到 5 分钟),并提供强大而全面的搜索功能。

      因此,在 Firebase 围绕查询推出一些改变游戏规则的功能之前,我建议一开始就使用 checking out this approach,而不是尝试通过其他方式来增加搜索功能。

      【讨论】:

        猜你喜欢
        • 2020-09-20
        • 1970-01-01
        • 2016-11-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-10-19
        • 2016-07-06
        相关资源
        最近更新 更多