Swift / Firebase - запрашивать имена пользователей под случайным uid, которые начинаются с ввода UITextField

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

Моя база данных настроена так:

Posts -|
   * Not needed for question *

Users -|
    412bjgaigb-2b41jb4-12j4bj214b -|
          Profile-Url: "https://link-to-image.com"
          Username: "RandomUser"
    3nj2b5io32-b4jk12b412-4124jke -|
          Profile-Url: "https://link-to-image.com"
          Username: "NewPerson"
    h8abgbbuag-n1nj21b1uj-jb41jb5 -|
          Profile-Url: "https://link-to-image.com"
          Username: "RedDawn"

В моих правилах базы данных Firebase он установлен как:

"rules": {
   ".read": true,
   ".write": true,
   "Users": {
      "$userid": {
         ".indexOn": ["Username"]
      }
   }
 }

В Swift мой код:

var strSearch = textfield.text!
ref.child("Users").queryOrdered(byChild: "Username").queryStarting(atValue: strSearch).queryEnding(atValue: "\(strSearch)\\uf8ff").observeSingleEvent(of: .value) { (snapshot) in
    print(snapshot.value)
}

Приведенный выше код запускается каждый раз при изменении текстового поля, но он возвращает каждого пользователя в узле «Пользователи». База данных большая, и я не хочу, чтобы мое приложение получало всех пользователей в базе данных.

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

Пример:

Пользователь вводит "R" внутри текстового поля.

Функция должна выводить только RandomUser и RedDawn.


person Spencer Villarreal    schedule 28.10.2020    source источник


Ответы (1)


Решение

Я нашел этот ответ, чтобы помочь с запросом только строк с префиксом строки поиска с использованием символа ~.

Используйте .queryStarting(atValue: strSearch).queryEnding(atValue: "\(strSearch)~")

Также я бы изменил ваши правила так, чтобы ".indexOn": ["Username"] находился за пределами вашего $userid.

{
  "rules": {
      ".read": true,
      ".write": true,
      "Users": {
          ".indexOn": ["Username"],
          "$userid": { }
      }
  }
}

Проблема

Единственная проблема, похоже, заключается в том, что имена пользователей, которые вы запрашиваете, чувствительны к регистру. Я не думаю, что в Firebase есть какой-либо встроенный способ нечувствительности к регистру при запросах. Если вам нужна эта функция, я бы предложил сохранить второе поле имени пользователя с версией в нижнем регистре для улучшения запросов. Вероятно, есть лучший подход где-нибудь еще в StackOverflow для этой проблемы.

Выполнение

Если вы в настоящее время отправляете запрос каждый раз, когда текстовое поле изменяется, могу ли я предложить использовать метод publisher и debounce () из инфраструктуры Combine. Таким образом, вы сможете отправлять запросы только тогда, когда пользователь ненадолго приостанавливает ввод. Увеличение интервала в методе устранения дребезга приведет к менее быстрым результатам, но не к такому количеству запросов к базе данных.

Я создал небольшой контроллер представления, который вы можете использовать в своем тестовом проекте.

import UIKit
import Combine
import FirebaseDatabase

class ViewController: UIViewController {
    
    var field = UITextField()
    
    var bag = Set<AnyCancellable>()
    
    init() {
        super.init(nibName: nil, bundle: nil)
        self.setup()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func loadView() {
        view = UIView()
        view.backgroundColor = .white
    }
    
    func setup() {
        
        //MARK: Receive Text Changes from Field
        
        NotificationCenter.default.publisher(
            for: UITextField.textDidChangeNotification,
            object: field
        )
        .debounce(for: 0.5, scheduler: DispatchQueue.main)
        .sink { [weak self] (notification) in
            guard let text = (notification.object as? UITextField)?.text else { return }
            self?.sendQuery(strSearch: text)
        }
        .store(in: &bag)
        
        
        //MARK: UISetup
        
        view.backgroundColor = .white
        
        view.addSubview(field)
        field.frame = CGRect(x: 300, y: 300, width: 250, height: 42)
        field.backgroundColor = .blue
        
    }
    
    func sendQuery(strSearch: String) {
        if strSearch.isEmpty { return }
        
        Database.database().reference().child("Users")
            .queryOrdered(byChild: "Username")
            .queryStarting(atValue: strSearch)
            .queryEnding(atValue: "\(strSearch)~")
            .observeSingleEvent(of: .value)
        { (snapshot) in
            if let val = snapshot.value {
                print(val)
            }
        }
    }

}


person KissTheCoder    schedule 05.11.2020