Получение определенного дочернего значения только из узлов, в которых присутствует UID пользователя

Я работаю над приложением группового чата, и у меня возникают проблемы при попытке сделать конкретный запрос к базе данных Firebase.

Мне нужно получить все профильные фотографии пользователей в комнате. Но только комнаты, частью которых является текущий пользователь.

private func observeRooms() {

    let databaseRef = FIRDatabase.database().reference()
    let groupRef = databaseRef.child("groups")

    guard let uid = FIRAuth.auth()?.currentUser?.uid else {return}
    let queryRef = groupRef.queryOrdered(byChild: "participants/\(uid)").queryEqual(toValue: nil)

    queryRef.observe(.childAdded, with: { snapshot in

        let roomDict = snapshot.value as! [String: AnyObject]
        print("roomDict: \(roomDict)")
        let id = snapshot.key

        let avatar = roomDict["profilePicture"] as! String
    })
}

Очевидно установка queryEqual(toValue: nil) возвращает все комнаты, частью которых текущий пользователь НЕ является - противоположность того, что мне нужно. Я знаю обратное будет проверять queryEqual(toValue: true), но : true не отображается в базе данных.

Вот как я добавляю узел к "группам" в Firebase:

        // Start group node for new room
        let groupRef: FIRDatabaseReference = FIRDatabase.database().reference().child("groups")
        let roomID = newRoomRef.key
        let groupRoomRef = groupRef.child(roomID)
        let groupDict = ["roomName" : roomName, "participants": [uid : true]] as [String : Any]
        groupRoomRef.setValue(groupDict)

И вот как структура данных заканчивается:

"groups" : {
  "-KkGzZ7frbnXmImt0JpV" : {
    "participants" : {
      "tzfHgGKWLEPzPU9GvkO4XE1QKy53" : {
        "gender" : "male",
        "handle" : "Testing",
        "name" : "Test User",
        "profilePicture" : "https://graph.facebook.com/*removed*/picture?type=large&return_ssl_resources=1",
        "status" : "F8B016"
      }
    },
    "roomName" : "Test Room"
  },

Как я могу правильно profilePicture значения для всех пользователей в комнате, только для групп, в которых участвует UID текущего пользователя?

1 ответ

Вы на правильном пути. Когда используешь queryEqual Ваш запрос должен соответствовать значению, фактически присутствующему в базе данных. К сожалению, это становится сложным, когда запрашиваемые значения являются сложными объектами. На самом деле я не уверен, что функция будет работать, даже если вы действительно соответствуете целому значению объекта. Проблема здесь в том, что вы пытаетесь искать объекты по наличию дочернего ключа, вместо того, чтобы фактически сортировать или сопоставлять их значения. Это не совсем подходит для случая использования любого из orderBy методы.

Есть несколько способов обойти это, упорядоченные по усилию.

Во-первых, вы можете воспользоваться порядком сортировки, чтобы получить только тех, у кого есть какой-либо объект с именем UID. Поскольку Firebase сначала сортирует пустые значения, затем примитивы и, наконец, объекты, вы должны иметь возможность упорядочить по потомкам и начать с true (или любой примитив), чтобы получить все экземпляры объекта с этим ключом (при условии, конечно, что вы не сохраняете UID: true в любом месте).

groupRef.queryOrdered(byChild: "participants/\(uid)").queryStartingAtValue(true)

Во-вторых, продублируйте UID как ключ внутри объекта со значением true так что вы можете сортировать по нему напрямую. Обратите внимание на дополнительный шаг в запросе.

"groups" : {
  "-KkGzZ7frbnXmImt0JpV" : {
    "participants" : {
      "tzfHgGKWLEPzPU9GvkO4XE1QKy53" : {
        "tzfHgGKWLEPzPU9GvkO4XE1QKy53" : true,
        ...

groupRef.queryOrdered(byChild: "participants/\(uid)/\(uid)").queryEqual(toValue: true)

Наконец, и это то, что я рекомендую, пересмотреть структуру данных. Вы вкладываете много данных в эту коллекцию коллекций, что сделает ваши запросы и обновления громоздкими. Firebase работает лучше, когда вы денормализуете свои данные, предпочитая плоские / неглубокие структуры с некоторым дублированием простых данных. В вашем случае вместо хранения данных профиля пользователя внутри их членства в группе у вас может быть набор групп и другой набор пользователей, причем каждая группа содержит только список идентификаторов UID для своих членов и наоборот. Пример в документации очень похож на ваш случай с участием в чатах. В этот момент ваши UID (и групповые идентификаторы, если вы вместо этого запрашиваете пользователей) будут иметь значение true так что вы можете снова использовать простой запрос значения.

"groups" : {
"-KkGzZ7frbnXmImt0JpV" : {
  "participants" : {
    "tzfHgGKWLEPzPU9GvkO4XE1QKy53" : true
    ...

"users" : {
"tzfHgGKWLEPzPU9GvkO4XE1QKy53" : {
  "groups" : {
    "-KkGzZ7frbnXmImt0JpV" : true
    ...

groupRef.queryOrdered(byChild: "participants/\(uid)").queryEqual(toValue: true)

Другие вопросы по тегам