如何查询Firebase中所有子项中具有特定值属性的方法

36

我有一个数据结构,其中待办事项被组织成遵循路径 /todos/uid/。

{
  "metausers" : {
    "simplelogin:1" : {
      "displayName" : "John Doe",
      "provider" : "password",
      "provider_id" : "1"
    },
    "simplelogin:2" : {
      "displayName" : "GI Jane",
      "provider" : "password",
      "provider_id" : "2"
    }
  },
  "todos" : {
    "simplelogin:1" : {
      "-JUAfv4_-ZUlH7JqM4WZ" : {
        "completed" : false,
        "done" : false,
        "group" : false,
        "private" : false,
        "subject" : "First"
      },
      "-JUAfveXP_sqqX32jCJS" : {
        "completed" : false,
        "done" : false,
        "group" : false,
        "private" : true,
        "subject" : "Second"
      },
      "-JUAfwXnMo6P53Qz6Fd2" : {
        "completed" : false,
        "done" : false,
        "group" : false,
        "private" : false,
        "subject" : "Third"
      }
    },
    "simplelogin:2" : {
      "-JUAg9rVemiNQykfvvHs" : {
        "completed" : false,
        "done" : false,
        "group" : false,
        "private" : false,
        "subject" : "Q first"
      },
      "-JUAgAmgPwZLPr2iH1Ho" : {
        "completed" : false,
        "done" : false,
        "group" : false,
        "private" : false,
        "subject" : "Q second"
      },
      "-JUAgBfF8f7V5R5-XgrY" : {
        "completed" : false,
        "done" : false,
        "group" : false,
        "private" : true,
        "subject" : "Q third"
      }
    }
  }
}

我想查询所有 private:true 的待办事项记录,使用 firebase(angularfire)是否可以实现,并且应该如何操作?或者我是否需要再次规范化数据结构并将路径/ private安排好,以避免沿着todos走下去?


1
Firebase可以根据节点的名称或节点的优先级查询数据。如果您的“private”属性不是这两者之一,那么您必须将其提升为这样的属性(例如通过使用每个节点的“private”值调用“setPriority”),或者您必须提供一个索引,该索引按值提供数据列表(例如具有所有非私有待办事项名称的节点)。请参见https://www.firebase.com/blog/2013-04-12-denormalizing-is-normal.html、https://www.firebase.com/blog/2013-10-01-queries-part-one.html和https://www.firebase.com/blog/2014-01-02-queries-part-two.html。 - Frank van Puffelen
谢谢您的回答,我明白了。 - Denis
1
嗨@Denis,我下面的解决方案应该适用于您。我将您的JSON导入Firebase进行了检查。不确定为什么没有人提到这一点。如果您能更新答案以供未来的人(像我一样)使用,那就太好了。 - Matt
也许在2014年,.orderByChild方法还没有出现,但是在2020年它已经存在并且可以使用。感谢Matt! - ProfDFrancis
3个回答

57
假设您拥有uid,使用以下代码应该很简单:
var uid = "simplelogin:1";
var todosRef = new Firebase("https://yourdb.firebaseio.com/todos/" + uid);
var privateTodosRef = todosRef.orderByChild("private").equalTo(true);
var privateTodos;

privateTodosRef.on("value", function(response) {
  privateTodos = response.val();
});

这应该返回一个包含该用户所有私有待办事项的对象,按其待办事项键(即"-JUAfv4_-ZUlH7JqM4WZ")组织。如果您想使用Angularfire,可以将其包装在$firebaseArray中,并按如下方式进行分配:

$scope.privateTodos = $firebaseArray(privateTodosRef);

这里有一个参考链接,可以了解更多关于复杂查询的信息,正如其他回答中提到的,使用优先级和重构可以进行一些不错的优化。

祝编码愉快!


5
这正是TS(以及我)正在寻找的。请点赞,因为这应该是正确的答案! - Boy
实际上,这是我发现的唯一过滤数据的方法。从语义上讲,它并不一致,因为语法中没有关于过滤的标志。我认为Firebase目前缺乏很多真实世界的功能。在开始时考虑每种可能的查询情况来构建复杂的数据结构是不现实的。 - Daniel Leiszen
您可能还需要在数据库规则中添加一个 indexOn 字段。https://firebase.google.com/docs/database/security/indexing-data - Prajoth

17

在 Firebase 中没有 WHERE 子句。查看此线程以获取有关通过多个字段进行搜索的结构提示,此线程有关数据库样式查询,此博客讨论查询和文档

您的第一种方法应该是将数据分段,以便读取。比如以下内容:

/todos/public
/todos/private
/todos/completed

你还可以按照文档所述利用优先级,然后根据优先级获取项目。

如果列表少于一千个,这应该是数据正确分区的情况下,您也可以在客户端上直接获取待办事项列表并进行筛选--这对于像Angular这样的绑定库处理短集合时是一个非常好的选择。


谢谢Kato的回答和链接。是的,我正在使用Angular,并计划使用您的辅助工具。我知道我可以像数组一样获取所有列表并进行过滤,如果不太大的话。我只是不想专注于一个点,而是尝试找到其他方法。 - Denis

3

所有Firebase中的数据都可以通过URL进行访问。如果您转到Firebase仪表板(Firebase Dashboard)查看数据模型(Forge),并单击您感兴趣的属性,您将被重定向到一个URL,通过该URL可以访问此特定数据,例如https://myapp.firebaseio.com/todos/simplelogin:1/-JUAg9rVemiNQykfvvHs/private。请记住这一点,您可以使用AngularFire访问此数据。


谢谢你的回答,Alex。是的,我认为在你、Kato和Frank的回答之后,我对下一步的学习以及如何考虑去规范化有了很好的概述。 - Denis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接