坚持为我的firebase数据库设计架构

时间:2014-06-24 16:13:43

标签: firebase firebase-realtime-database

我来自SQL背景,所以我在设计NoSQL firebase架构时遇到了问题。我以前能够使用" WHERE"来查询任何内容。在firebase中这样做似乎更加困难(虽然性能很容易弥补它!)。

我正在存储"追踪"歌曲的对象。这些对象具有键/值对,例如artist_name,曲目标题,流派,等级,created_date等,如下所示:

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

我网站上的默认行为是列出所有这些曲目,最新添加的曲目显示在列表顶部。我可以设置我的优先级来创建并将其变为负数(创建* -1)以实现我认为的这种效果。

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

  • 检索所有具有摇滚,流行或嘻哈类型的曲目。

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

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

  1. 通过" ID" value,其中包含" firebaseURL.firebaseio.com/tracks/id"的物理位置,在我的情况下,在我添加曲目时会自动为我选择。这是可以的(我认为),因为我有列出详细信息的单个跟踪页面的页面,我网站上的URL类似于" www.mysite.com/tracks/-JPl1zwOzjqoM8xDTFll"。

  2. 使用$优先级,在我的情况下,我已用于"创建"价值,以便按正确的日期顺序订购我的清单。

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

    我阅读博客"将数据归一化为正常" (https://www.firebase.com/blog/2013-04-12-denormalizing-is-normal.html),我想我明白了。从Anant所描述的,实现我想要的一种方法可能是在firebase中为一个类型创建一个新对象并列出那里的所有轨道,如下所示:

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

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

    这是有道理的,我不会介意这种方法。但这只有在用户想要从一种类型中选择所有曲目时才有效。如果他们想要从BOTH摇滚和流行音乐中获得所有曲目怎么办?每次有人提交任何类型的歌曲时,我是否必须存储另一个名为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架构了。我已经做了一些改进,但随着我的应用程序变得越来越大,更改它会变得更加昂贵并且消耗更多时间。如果我能在最后一段时间内清除这些问题,我花了很多时间重新编写其余的代码以便再次匹配它,那就太好了。

    感谢您对此提供任何帮助,我们非常感谢。如果您需要其他信息,请告诉我。

2 个答案:

答案 0 :(得分:5)

Firebase将在明年推出对查询API的大量补充。上下文搜索(其中foo类似于 bar )可能永远不会成为实时数据中的一大亮点 - 它很慢而且很麻烦。

关于SQL查询和Firebase中的等效模式,有一篇由两部分组成的博客文章。我建议你give it a read-through。第2部分特别讨论了Flashlight

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

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

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

答案 1 :(得分:0)

在上面的示例中,您构建了不同的层次结构并存储了一些数据,但只是将ID作为键放入。因此,当您将其转移到客户端时,您可能仍会按某些数据字段进行排序。

我想让Firebase使用多部分密钥为我处理排序。

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

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

假设用户选择了“Rock”类型,并在搜索框中键入“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,后面是前十个来自pop。如果这对你来说不够,你可以总是用相同的微小数据对象和可以选择作为搜索过滤器的每种独特的类型组合制作很多组合索引。不过,“磁盘很便宜,但用户的时间不是”,这是你的指导准则。