【问题标题】:Firebase database structureFirebase 数据库结构
【发布时间】:2016-12-21 17:28:33
【问题描述】:

我刚刚开始尝试使用 Firebase。当您习惯了关系数据库时,这真是令人头疼!

我正在尝试设计一个应用程序,允许用户通过条形码或名称搜索餐食并检索卡路里数量。此外,我需要能够存储用户吃的饭菜,并最终检索用户每天、每周或每月吃的饭菜。

我在想每顿饭都有一个唯一的 ID(例如 M1234 表示比萨饼),然后我会有 2 个查找部分 - 一个按条形码,一个按名称,因此有望涵盖搜索功能。

每个用户都会将吃过的饭菜按日期存储在吃过的“表”中(Firebase 数据库中“表”的正确术语是什么?),只需按 ID 引用饭菜。

这就是我设计数据库的方式。

  {
// Here are the users.
    "users": {
      "mchen": {
        "name": "Mary Chen",
        "email": "mary@chen.com",

        }
      },
      ...
    },
// Here are the meals eaten by date.
    "eaten": {
      "mchen": {
         // index Mary's meals in her profile /eaten/mchen/meals/20161217 should return 'M1234' (pizza) and 'M8765' (chips)
        "meals": {
          "20161217": {
             "M1234": true,
             "M8765": true
          },
          "20161218": {
             "M2222": true,
             "M8765": true
          }
      },
      ...
    },
// Here are the meals with calorie information.
    "meals": {
      "M1234": {
        "name": "Pizza"
        "calories": 400
      },
      "M2222": {
        "name": "Curry"
        "calories": 250
      },
      "M8765": {
        "name": "Chips"
        "calories": 100
      },
    },
// Here is the barcode lookup
    "barcode-lookup": {
      "12345678": {
        "id": "M1234"
      },
      "87654321": {
        "id": "M2222"
      },
      "11223344": {
        "id": "M8765"
      }
    },
// Here is the name lookup
    "name-lookup": {
      "Chips": {
        "id": "M8765"
      },
      "Pizza": {
        "id": "M1234"
      },
      "Curry": {
        "id": "M2222"
      }
    }

  }

看起来合理还是有明显缺陷?

【问题讨论】:

标签: database firebase firebase-realtime-database nosql


【解决方案1】:

您需要利用 .childByAutoId() 并让 Firebase 创建父键名称。最佳做法是取消您的子数据与父节点的关联,并允许 Firebase 为父节点创建“随机”密钥,这样可以实现。

除此之外,通常会创建一个 /users 节点,每个用户的父节点将是 Firebase 在首次创建用户时创建的 uid。

在您的原始结构中,有一个条形码和名称查找,我已将其集成到以下结构中以降低复杂性。

users
  uid_0
    name: "Mary Chen",
    email: "mary@chen.com"
  uid_1
    name: "Larry David"
    email: "ldavid@david.com"

然后是餐厅

dining
  -Yuiia09skjspo
    dining_timestamp: "20161207113010"
    Y79joa90ksss: true
    Yjs9990kokod: true
    user: uid_0
    uid_timestamp: "uid_0_ 20161207113010"
  -Yi9sjmsospkos
    dining_timestamp: "20161207173000"
    Y79joa90ksss: true
    Yjs9990kokod: true
    user: uid_1
    uid_timestamp: "uid_1_ 20161207173000"

以及用户可以选择的膳食

meal
  -Y79joa90ksss
    name: "Pizza"
    calories: "400"
    barcode: "008481816164"
  -Yjs9990kokod
    name: "Burger"
    calories: "520"
    barcode: "991994411815"

如您所见,用餐节点包含每个用户的用餐事件(因此所有用餐事件都在一个节点中)

这使您可以查询各种事物:

All dining for all users by date or range of dates.
All dining that contain a certain meal
All meals by a user
->The cool one<- all dining for a specific user within a date range.

一个遗漏是搜索包含两餐的用餐,但是,解决方案也在这个答案中。

总而言之,您的结构是合理的 - 只需稍作调整即可。

【讨论】:

  • 感谢杰伊的深入回答。使用你的结构,如果我只知道条形码,我是否能够快速检索一顿饭所含的卡路里?对不起,如果这是一个愚蠢的问题——我将使用 AngularJS 来编写这个应用程序,但还没有真正掌握实际可以做什么。我认为最好先尝试设计数据库。
  • @Damian 我认为你的方向是正确的!您可以查询膳食节点的任何名称、卡路里或条形码,所以可以。此外,您还可以使用 .startingAt 和 .endingAt 查询例如查询膳食节点以获取介于 300 到 500 卡路里之间的任何膳食。此外,如果您想知道单次用餐体验中的总卡路里,您将读取该用餐节点,该节点将检索时间戳、uid 以及包括哪些餐点(通过引用)。然后,您将通过他们的参考查询每餐,以获取每餐的卡路里。
  • 从技术上讲,条形码应该是唯一的,因此它们可以用作餐点节点中餐点的键。但是,最好还是将父名称与子数据分离。
  • 再次感谢杰。我将根据您的设计将一些代码放在一起。达米安
  • @Jay 嘿,你介意看看这个问题吗? stackoverflow.com/questions/44962262/…
【解决方案2】:

结构看起来不错(尽管我会让 firebase 生成 id)。唯一不会像您期望的那样工作的是搜索。根据您的数据,如果我搜索 pizza,您将无法编写返回 Pizza 条目的查询。我的建议是要么使用 Algolia(或类似的东西)进行搜索,要么使用你的名字 lowerCased 滚动另一个键,以使查询能够工作。运行自己的唯一问题是您将无法搜索 izz 之类的内容并让 Pizza 出现。请参阅我的回答 Firebase - How can I filter similarly to equalTo() but instead check if it contains the value? 了解如何进行搜索。

【讨论】:

  • 根据结构,我认为 OP 不会搜索 Pizza。他将搜索 M1234,它会工作得很好。
  • 谢谢马修。我一定会让 Firebase 为我生成 id,感谢您的搜索信息 - 搜索以搜索字符串开头的餐点可能就足够了,因此以 '\uf8ff' 结尾的食物可能对我来说很有效!
猜你喜欢
  • 2019-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-21
  • 1970-01-01
相关资源
最近更新 更多