0

FirebaseをUISearchControllerデリゲートに組み込む方法についての情報はありますか?私はそれについての固い情報を見つけることができません。おそらく何千人もの従業員がいるかもしれません。FirebaseとUISearchbarControllerはクライアントではなくサーバ経由で検索します。 - スウィフトiOS

検索コントローラの代理人updateSearchResultsForSearchControllerを使用し、NSPredicateを使用してNSUserDefaultsを使用していてもFirebaseを使用している場合は、私が探しているものをフィルタリングする方法を知っています。

私はFirebaseDatabaseに保存されたカスタムデータモデルオブジェクトを持っていると私はオブジェクト内の次のプロパティのすべてを検索したい私の質問

にいくつかのより多くのコードを追加しました。

lastName 
idNumber 
deptNumber 
position 

私が探している文字列全体が表示されるまで、第1表のセル内の部分文字列を表示する必要があり、これらのプロパティのいずれかを検索します。したがって、文字「S」を入力すると、「S」で始まるすべての従業員の姓が表示されます。私が "Sa"を入力すると、これらの文字にフィルタをかける "私の理解では、部分検索文字列を取得するのに、データは返されないが、データは返されない。

Anyway here are all code

私のオブジェクトは、次のとおりです。

class Employee{ 
var firstName: String? 
var lastName: String? 
var idNumber: String? 
var deptNumber: String? 
var position: String? 
} 

私のパス

-root 
    -users 
    -uid 
     |_"email":"emailAddress" 
     |_"userID":"uid" 
     |_"firstName":"firstName" 
     |_"lastName":"lastName" 
    -employees 
    -hireDate 
     -uid //this is the same uid from the users node so I know who's who 
     |_"firstName":"firstName" 
     |_"lastName":"lastName" 
     |_"idNum":"idNumber" 
     |_"deptNumber":"deptNumber" 
     |_"position":"position" 

マイルール:

ここで起きているのは、従業員が雇われた日で、電子メールアドレスとPWを使用して企業アカウントを作成するよう求められた日です。 同時に、 "hireDate"パスである子と最後に従業員 "uid"パスである "employees"パスが作成されます。この従業員「uidは」私は「従業員」からの検索したいパスノードである

{ 
    "rules": { 
     "users" : { 
      "$uid" : { 
       ".read": true, 
       ".write": "auth != null && auth.uid == $uid" 
      } 
     }, 
     "employees": { 
      "$hireDate": { 
       "$uid": { 
       ".read": true, 
       ".indexOn": ["lastName", "idNumber", "deptNumber", "position"] 
       } 
      } 
    } 
    } 
} 

マイsearchControllerここ

import UIKit 

class SearchController: UIViewController{ 

@IBOutlet var tableView: UITableView! 

var searchController: UISearchController! 
var employeesToFilter = [Employee]() 
var filteredSearchResults = [Employee]() 


override func viewDidLoad() { 
    super.viewDidLoad() 
    self.searchController = UISearchController(searchResultsController: nil) 

    self.tableView.delegate = self 
    //all searchController properties get set here no need to include them though 

    let ref = FIRDatabase.database().reference() 
    let employeeRef = ref.child("employees") 

    employeeRef?.queryOrderedByChild("lastName").queryStartingAtValue("\u{f8ff}").queryLimitedToFirst(20).observeEventType(.ChildAdded, withBlock: { 

     (snapshot) in 

     if let dict = snapshot.value as? [String:AnyObject]{ 

      let firstName = dict["firstName"] as! String 
      let lastName = dict["lastName"] as! String 
      let idNumber = dict["idNumber"] as! String 
      let deptNumber = dict["deptNumber"] as! String 
      let position = dict["position"] as! String 

      let employee = Employee() 
      employee.firstName = firstName 
      employee.lastName = lastName 
      employee.idNumber = idNumber 
      employee.deptNumber = deptNumber 
      employee.position = position 

      self.employeesToFilter.append(employee) 
     } 
    }) 
    self.tableView.reloadData() 
} 

override func viewDidAppear(animated: Bool) { 
    self.searchController.active = true 
} 

deinit { 
    self.searchController = nil 
} 

} 


//MARK:- TableView Datasource 
extension SearchBuildingController: UITableViewDataSource, UITableViewDelegate{ 

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
    return self.filteredSearchResults.count 
} 

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 
    let cell = self.tableView.dequeueReusableCellWithIdentifier("SearchCell", forIndexPath: indexPath) as! SearchCell 

    let searchString = self.filteredSearchResults[indexPath.row] 

    cell.firstNameLabel.text = searchString.firstName 
    cell.lastNameLabel.text = searchString.lastName 
    cell.idNumberLabel.text = searchString.idNumber 
    cell.deptNumberLabel.text = searchString.deptNumber 
    cell.positionLabel.text = searchString.position 
    return cell 
} 
} 

//MARK:- SearchController Delegates 
extension SearchController: UISearchResultsUpdating, UISearchBarDelegate, UISearchControllerDelegate{ 

func searchBarTextDidBeginEditing(searchBar: UISearchBar) { 
    tableView.reloadData() 
} 

func updateSearchResultsForSearchController(searchController: UISearchController) { 

    self.employeesToFilter.removeAll(keepCapacity: false) 
    self.filteredSearchResults.removeAll(keepCapacity: false) 

    let searchText = self.searchController.searchBar.text 

    let searchPredicate = NSPredicate(format: SELF.lastName CONTAINS [c] %@ OR SELF.idNumber CONTAINS [c] %@ OR SELF.deptNumber CONTAINS[c] %@ OR SELF.position CONTAINS [c] %@", searchText!, searchText!, searchText!, searchText!) 

    let array = (self.employeesToFilter as NSArray).filteredArrayUsingPredicate(searchPredicate) 
    self.filteredSearchResults = array as! [Employee] 

    tableView.reloadData() 
} 
} 
+0

「\ u {f8ff}」のみを検索するのではなく、それはあなたがそれを "開始する"基準を与えていないので意味を成さない。ですから、代わりに 'startingAtValue(" S ")'と 'endingAtValue(" S \ u {f8ff} ");'のようなものが必要です。 Firebaseで高度なファジー/コンテキスト検索を実装しようとすると、一般的にはそれが価値よりも複雑になります。適切な検索エンジンははるかに堅牢で、私の意見では、立ち上げて実行するのがはるかに複雑です。検索をFirebaseと統合する方法の例については、[懐中電灯](https://github.com/firebase/flashlight)を参照してください。 – Kato

+0

@Katoありがとう私はそれを探しています –

答えて

1

は、私はリストを構築Firebase使用してこれを達成した方法の例ですキャンパスのこのメソッドは、テーブルビューの前にあるすべてのデータを読み込み、検索とフィルタリングを容易にします。

私のキャンパスのオブジェクトは、IDと名前でかなりシンプルです。

struct Campus { 
    var id: String 
    var name: String 
} 

私は2つの配列を持っています。 1つは返されたすべてのキャンパスのリストを保持し、もう1つはフィルタリングされたキャンパスの配列です。

let campuses = [Campus]() 
let filteredCampuses = [Campus]() 

私はFirebaseからキャンパスをロードするように設定したメソッドを呼び出しました。検索を実行するときに

override func viewDidLoad() { 
    ... 

    getAllCampusesFromFirebase() { (campuses) in 
     self.campuses = campuses 
     dispatch_async(dispatch_get_main_queue(), { 
      self.tableView.reloadData() 
     }) 
    } 
} 

それから私は、検索バーから検索テキストにキャンパス名を比較したキャンパスを除外する。

func updateSearchResultsForSearchController(searchController: UISearchController) { 
    guard let searchText = searchController.searchBar.text else { 
     return 
    } 

    filteredCampuses = campuses.filter { campus in 
     return campus.name.lowercaseString.containsString(searchText.lowercaseString) 
    } 

    tableView.reloadData() 
} 

あなたはアップフロントのすべてのデータをロードしていない場合は、Firebaseはあなたが参照経路に基づいてデータをフィルタリングするために使用できることを呼び出すためにいくつかの便利なメソッドを提供します。 https://firebase.google.com/docs/database/ios/lists-of-data

queryStarting(atValue)またはqueryStarting(atValue:childKey:)これはおそらくこの場合に使用したいものです。

ref.queryStarting(atValue: Any?) 
ref.queryStarting(atValue: Any?, childKey: String?) 
+0

ありがとう。私は今日の検索で取り組んでいました。 DB内に何十億ものキャンパスオブジェクトがあれば、すべてのFBデータを配列に読み込むことは重大なパフォーマンス上の問題を引き起こすでしょう。 queryStart経由でdbから直接クエリを実行するには、大量のデータが存在する場合の方法と思われます。私は2つの場所で失われています。 1.どのようにして、キャンパス配列またはフィルターされた配列にqueryDataを取得しますか? 2.例えば、複数のプロパティを照会する方法キャンパスIDと名前の両方でどのようにクエリしますか?また、あなたが場所のプロパティを持っていた場合、それをどのように含めるのですか?これらは3つのdiff値です。 –

+0

1)queryDataを取得するには、 'ref.queryStarting(atValue).observeEvent(FIRDataEventType:with)'を検索しているパスに 'observe(FIRDataEventType:with)'メソッドを実行します。これにより、クエリのデータが返され、そのデータでフィルタされた配列が読み込まれます。 2)複数のクエリを取得するには、クエリ 'ref.queryStarting(atValue).queryStarting(atValue)'などを連鎖させることができます。これをまだ試していませんが、クエリがANDまたはORとして複数の値。 3)場所検索のために私はGeoFireを使い始めました。 – Donny

+0

私は答えをより多くのコードで更新しました。チャンスを得たら、あなたの考えを教えてください。 –

関連する問題