Ваша текущая структура данных отлично подходит для поиска участников определенного чата. Это не очень хорошая структура для поиска обратного: чаты, в которых участвует пользователь.
Несколько проблем здесь:
Чат может иметь несколько участников, поэтому вы смоделировали это как массив. Но на самом деле это не идеальная структура данных. Вероятно, каждый участник может быть только в чате один раз. Но, используя массив, я мог бы:
participants: ["puf", "puf"]
Это явно не то, что вы имеете в виду, но структура данных позволяет это. Вы можете попытаться обеспечить это в коде и правилах безопасности, но было бы проще, если бы вы начали с структуры данных, которая неявно соответствует вашей модели.
Мое эмпирическое правило: если вы обнаружите, что пишете array.contains()
, вы должны использовать набор.
Набор представляет собой структуру, в которой каждый ребенок может присутствовать не более одного раза, поэтому он естественным образом защищает от дубликатов. В Firebase вы моделируете набор как:
participants: {
"puf": true
}
Здесь true
здесь действительно просто фиктивное значение: важно то, что мы переместили имя на ключ. Теперь, если я попытаюсь снова присоединиться к чату, это будет noop:
participants: {
"puf": true
}
И когда вы присоединитесь:
participants: {
"john": true,
"puf": true
}
Это самый прямой представление вашего требования: коллекция, которая может содержать только каждого участника один раз.
. С указанной структурой вы могли запросить для чатов, в которых вы находитесь:
ref.child("chats").orderByChild("participants/john").equalTo(true)
Проблема заключается в том, что для этого требуется, чтобы вы определяли индекс для `members / john ':
{
"rules": {
"chats": {
"$chatid": {
"participants": {
".indexOn": ["john", "puf"]
}
}
}
}
}
Это будет работать и но теперь каждый раз, когда кто-то новый присоединяется к чат-приложению, вам нужно добавить еще один индекс. Это явно не масштабируемая модель. Нам нужно будет изменить нашу структуру данных, чтобы разрешить требуемый запрос.
Второе правило: моделируйте ваши данные, чтобы отразить то, что вы показываете в своем приложении.
Поскольку вы ищете показать список чатов для пользователя, сохранить чаты для каждого пользователя:
userChatrooms: {
john: {
chatRoom1: true,
chatRoom2: true
},
puf: {
chatRoom1: true,
chatRoom3: true
}
}
Теперь вы можете si просто определите свой список чатов с помощью:
ref.child("userChatrooms").child("john")
И затем перейдите по клавишам, чтобы получить каждую комнату.
Вам понравится иметь два соответствующих списка в вашем приложении:
Кроме того, в базе данных есть оба списка.
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
.