javascript - Firebase 查询子项的子项是否包含值

标签 javascript angular firebase firebase-realtime-database angularfire2

表的结构是:

  • 聊天
  • --> 随机数
  • -->--> 参与者
  • -->-->--> 0: 'name1'
  • -->-->--> 1: 'name2'
  • -->--> 聊天项

等等

我正在尝试做的是查询聊天表,以通过传入的用户名字符串查找包含参与者的所有聊天。

这是我目前所拥有的:

 subscribeChats(username: string) {
    return this.af.database.list('chats', {
        query: {
            orderByChild: 'participants',
            equalTo: username, // How to check if participants contain username
        }
    });
 }

最佳答案

您当前的数据结构非常适合查找特定聊天的参与者。然而,它不是一个很好的逆向结构:用户参与的聊天。

这里有几个问题:

  • 你正在将一个集合存储为一个数组
  • 只能在固定路径上建立索引

集合与数组

聊天可以有多个参与者,因此您将其建模为一个数组。但这实际上并不是理想的数据结构。可能每个参与者只能参与一次聊天。但是通过使用数组,我可以:

participants: ["puf", "puf"]

这显然不是您想要的,但数据结构允许这样做。您可以尝试在代码和安全规则中保护这一点,但如果您从隐含地更好地匹配您的模型的数据结构开始,这会更容易。

我的经验法则:如果您发现自己在编写 array.contains(),您应该使用集合

集合是一种结构,其中每个 child 最多只能出现一次,因此它自然可以防止重复。在 Firebase 中,您可以将集合建模为:

participants: {
  "puf": true
}

这里的 true 实际上只是一个虚拟值:重要的是我们已经将名称移动到键中。现在,如果我再次尝试加入此聊天,那将是空话:

participants: {
  "puf": true
}

以及您何时加入:

participants: {
  "john": true,
  "puf": true
}

这是您要求的最直接表示:一个只能包含每个参与者一次的集合。

您只能索引已知属性

使用上述结构,您可以查询您正在进行的聊天:

ref.child("chats").orderByChild("participants/john").equalTo(true)

问题是这需要你在 `participants/john"上定义一个索引:

{
  "rules": {
    "chats": {
      "$chatid": {
        "participants": {
          ".indexOn": ["john", "puf"]
        }
      }
    }
  }
}

这会工作并且表现出色。但现在每次有新人加入聊天应用程序时,您都需要添加另一个索引。这显然不是一个可扩展的模型。我们需要更改我们的数据结构以允许您想要的查询。

反转索引 - 向上拉类别,展平树

第二条经验法则:对数据建模以反射(reflect)您在应用中显示的内容

由于您希望为用户显示聊天室列表,因此为每个用户存储聊天室:

userChatrooms: {
  john: {
    chatRoom1: true,
    chatRoom2: true
  },
  puf: {
    chatRoom1: true,
    chatRoom3: true
  }
}

现在您可以简单地确定您的聊天室列表:

ref.child("userChatrooms").child("john")

然后遍历 key 以获取每个房间。

您会希望在您的应用中有两个相关列表:

  • 特定用户的聊天室列表
  • 特定聊天室的参与者列表

在这种情况下,您还将在数据库中拥有这两个列表。

chatroomUsers
  chatroom1
    user1: true
    user2: true
  chatroom2
    user1: true
    user3: true
userChatrooms
  user1:
    chatroom1: true
    chatroom2: true
  user2:
    chatroom1: true
  user2:
    chatroom2: true

我已将这两个列表拉到树的顶层,因为 Firebase 不建议嵌套数据。

在 NoSQL 解决方案中拥有两个列表是完全正常的。在上面的示例中,我们将 userChatrooms 称为 chatroomsUsers 的倒排索引。

云端 Firestore

这是 Cloud Firestore 更好地支持此类查询的案例之一。它的 array-contains 运算符允许过滤数组中具有特定值的文档,而 arrayRemove 允许您将数组视为一个集合。有关更多信息,请参阅 Better Arrays in Cloud Firestore .

关于javascript - Firebase 查询子项的子项是否包含值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40656589/

相关文章:

node.js - 使用 Angular 版本 2.4.9、TypeScript 和 Webpack 版本 2.2.1 时,类型 'map' 上不存在属性 'Observable<Response>'

javascript - 如何修复 "Property ' getAll' 在类型 'typeof firestore' 上不存在“

iOS - Firebase 过滤器查询

ios - 如何使用 Swift 代码检索快照计数

javascript - ngif什么时候触发?

javascript - 与/b 一起使用时,替换函数无法识别西里尔字符

javascript - 使用 switchMap 的 Angular 4 RxJS 轮询

html - ngIf 仍然在 false 条件下渲染 div

javascript - jQuery 验证,仅限数值

javascript - Underscore.js 对象转数组