用于复杂查询的Firebase。不行吗?

时间:2017-03-08 13:35:29

标签: firebase firebase-realtime-database nosql

我已经从parse-server转移到firebase用于我的新项目,但是在项目中我已经开始认为这是一个坏主意。

基本上,我正在创建一个应用程序,人们可以在其中发布有关他们镇上的音乐会的信息。

我的第一个挑战是过滤事件,因此用户只能在他/她自己的城镇中获取事件。我通过构建城市之后的数据来做到这一点:

{
    concerts: {
        "New york": {
            ...,
            ...
        }, 
        "Chicago": {
            ...,
            ...
        }
    }
}

然后我想我需要另一种音乐会类型的过滤器,例如摇滚,流行音乐等。所以我虽然做了另一次重组。但是,可能需要再增加5到10个过滤器,并且很难以良好的方式构建数据库。

我关于多个查询,但不允许这样做:

firebase.database().ref("concerts")
.orderByChild("type").equalTo("rock")
.orderByChild("length").equalTo("2")
.orderByChild("artist").equalTo("beatles")

我考虑过从服务器获取所有内容,然后在客户端中过滤结果。不过我看到了两个问题:

  1. 可能会下载大量不必要的数据。
  2. 某些音乐会只会锁定某些用户(例如已经参加过至少10场其他音乐会的用户),并且可能存在将这些音乐会拉回到用户不被允许看到它们的安全方面。
  3. 我考虑过将过滤器组合起来创建查询键,例如this,但是使用10多个过滤器,它会变得复杂。

    是否有解决方案或者我应该忘记这个用例的firebase?

    提前致谢

2 个答案:

答案 0 :(得分:4)

可以在Firebase中制作难以置信的复杂查询。数据需要存储在一个有待查询的结构中,最重要的是,不要害怕重复数据。

例如,假设我们有一个应用程序,使用户可以选择特定年份和月份,特定城市和特定类型的音乐会。

有3个参数

YEAR_MONTH 市 流派

UI首先查询用户以选择城市

Austin

然后用户界面要求选择年份和月份

201704

然后是一种类型

Rock

您的Firebase结构如下所示

concerts
  concert_00
   city: Memphis
   year_month: 201706
   genre: Country
   city_date_genre: Memphis_201606_Country
  concert_01
   city: Austin
   year_month: 201704
   genre: Rock
   city_date_genre: Austin_201704_Rock
  concert_02
   city: Seattle
   year_month: 201705
   genre: Disco
   city_date_genre: Seattle_201705_Disco

您的用户界面已经在用户中查询了查询信息,并使用该信息构建查询字符串

Austin_201704_Rock

然后查询' city_date_genre'该字符串的节点,您有数据。

如果用户想要了解2017年4月奥斯汀的所有音乐会,该怎么办

queryStartingAt("Austin_201704").queryEndingAt("Austin_201704")

您可以通过添加另一个查询节点并更改数据的顺序

来轻松扩展此功能
concerts
  concert_00
   city: Memphis
   year_month: 201706
   genre: Country
   city_date_genre: Memphis_201606_Country
   city_genre_date: Memphis_Country_201606

根据用户选择数据的顺序,您可以查询关联的节点。

添加额外的节点是一个很小的数据,并允许对您需要的数据进行非常开放的查询。

答案 1 :(得分:0)

我看到这是一篇旧帖子,但我想借此机会将遇到类似 Firebase 问题的其他人指向 AceBase,它是 Firebase 实时数据库的免费开源替代品. Firebase 中缺乏适当的查询和索引选项是构建 AceBase 的原因之一。使用 AceBase 可以让您像这样查询数据:

const snapshots = await db.ref('concerts')
  .query()
  .filter('city', '==', 'New York')
  .filter('date', 'between', [today, nextWeek]) // today & nextWeek being Dates
  .filter('genre', 'in', ['rock', 'blues', 'country'])
  .get();

因为 AceBase 支持索引,向查询字段添加 1 个或多个索引将使这些查询运行得非常快,即使有数百万条记录。它支持简单索引,但也支持全文和地理索引,因此您还可以使用位置和关键字查询您的数据:

.filter('location', 'geo:nearby', { lat: 40.730610, long: -73.935242, radius: 10000 }) // New York center with 10km radius
.filter('title', 'fulltext:contains', '"John Mayer" OR "Kenny Wayne Shepherd"')

如果您想限制结果以允许分页,只需添加跳过和限制:.skip(80).limit(20)

此外,如果您想让查询提供实时结果,以便任何新添加的音乐会立即通知您的应用 - 只需添加事件侦听器即可将其升级为实时查询:

const results = await db.ref('concerts')
  .filter('location', 'geo:nearby', { lat: 40.730610, long: -73.935242, radius: 10000 })
  .on('add', addConcert)
  .on('remove', removeConcert)
  .get();

function addConcert(match) {
  results.push(match.snapshot);
  updateUI();
}
function removeConcert(match) {
  const index = results.findIndex(r => r.ref.path === match.ref.path);
  results.splice(index, 1);
  updateUI();
}

如果您想了解有关 AceBase 的更多信息,请访问 npm:https://www.npmjs.com/package/acebase。 AceBase 是免费的,其全部源代码可在 GitHub 上获得。玩得开心!