Ответ 1
Несколько проблем здесь:
- вы сохраняете набор как массив
- вы можете индексировать только по фиксированным путям
Установить vs array
В чате может быть несколько участников, поэтому вы смоделировали это как массив. Но на самом деле это не идеальная структура данных. Вероятно, каждый участник может быть только в чате один раз. Но, используя массив, я мог бы:
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
}
}
Теперь вы можете просто определить свой список чатов с помощью:
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
.