简体   繁体   English

处理由于 Firebase 查询中元素数量过多而导致的内存使用情况

[英]Dealing with memory usage due to high element count in Firebase query

I'm writing code that is appending elements from firebase to an array to perform a simple search using a textfield.我正在编写将元素从 firebase 附加到数组以使用文本字段执行简单搜索的代码。

The code for the method is below:该方法的代码如下:

 var filteredEvents = [Event]()
var eventsArray = [Event]()
fileprivate func fetchEvents(){
    print("Fetching events....")
    //create a reference to the location in the database that you want to pull from and observe the value there
    let ref = Database.database().reference().child("events")
    // this will retur a snapshot with all the data at that location in the database and cast the results as a dictionary for later use
    ref.observe(.value, with: { (snapshot) in
        guard let dictionaries = snapshot.value as? [String: Any] else{
            return
        }
        //does the job of sorting dictionary elements by key and value
        //displaying the key and each corresponding value
        dictionaries.forEach({ (key,value) in
           // print(key, value)
            //creating an eventDictionary to store the results of previous call
            guard let eventDictionary = value as? [String: Any] else{
                return
            }
            //will cast each of the values as an Event based off my included struct
            //Make sure to create a model it is the only way to have the data in the format you want for easy access
             let events = Event(currentEventKey: key, dictionary:eventDictionary)
            // appends that to the dictionary to create the dictionary of events
            self.eventsArray.append(events)
        })
        // will sort the array elements based off the name
        self.eventsArray.sort(by: { (event1, event2) -> Bool in
            return event1.currentEventName.compare(event2.currentEventName) == .orderedAscending
        })
        // will again reload the data
        self.collectionView?.reloadData()

    }) { (err) in
        print("Failed to fetch events for search")
    }
}

I personally did not think of the chance where I may have a great number of events.我个人没有想到我可能有很多活动的机会。 I won't be able to just append all 1000+ events to a dictionary.我将无法将所有 1000 多个事件附加到字典中。 That will ratchet my memory up.那会增加我的记忆力。 Is there anyway I could have the query respond to the text field.无论如何我可以让查询响应文本字段。 Also could anyone maybe help me with the line for the query that would perform this action but not destroy my memory?也有人可以帮助我执行此操作但不会破坏我的记忆的查询行吗?

"events" : {
"CCDS" : {
  "attend:count" : 1,
  "event:date" : {
    "end:date" : "08/09/2017",
    "end:time" : "7:00 PM",
    "start:date" : "08/09/2017",
    "start:time" : "5:00 PM"
  },
  "event:description" : "Happy hour is more joyful in the summer thanks to Center City District Sips, which offers discounted drinks and appetizers every Wednesday evening.  Catch up with old friends and make a few new ones as Center City’s best bars and restaurants host the summer’s happiest hour every Wednesday from 5-7 p.m.  Enjoy $5 cocktails, $4 wine, $3 beers and half-price appetizers at dozens and dozens of bars and restaurants.",
  "event:imageURL" :someURL",
  "event:location" : {
    "event:city" : "Philadelphia",
    "event:state" : "PA",
    "event:street:address" : "660 Chestnut St",
    "event:zip" : 19106
  },
  "event:name" : "Center City District Sips"
},
"MIA" : {
  "attend:count" : 1,
  "event:date" : {
    "end:date" : "09/03/2017",
    "end:time" : "7:00 PM",
    "start:date" : "09/02/2017",
    "start:time" : "12:00 PM"
  },
  "event:description" : "Budweiser Made in America Festival is an annual music festival held in Philadelphia and formerly simultaneously held in Los Angeles.Sponsored by Anheuser–Busch and produced by Live Nation, the event features several stages that continuously host live music from a wide range of genres including hip hop, rock, pop, R&B, and EDM.",
  "event:imageURL" : "someURL",
  "event:location" : {
    "event:city" : "Philadelphia",
    "event:state" : "PA",
    "event:street:address" : "Ben Franklin Parkway",
    "event:zip" : 19130
  },
  "event:name" : "Made In America"
}
  },

For example I want to pull all information about an event that I have searched for using the query.例如,我想提取有关我使用查询搜索过的事件的所有信息。 So if I begin to type in Made in America it will pull all relevant information from the events tab about that event因此,如果我开始输入 Made in America,它将从事件选项卡中提取有关该事件的所有相关信息

This is what I currently have这是我目前拥有的

fileprivate func fetchEvents(searchString: String){
    print("Fetching events....")
    //create a reference to the location in the database that you want to pull from and observe the value there
    let ref = Database.database().reference().child("events")
    // this will retur a snapshot with all the data at that location in the database and cast the results as a dictionary for later use
  let query = ref.queryOrdered(byChild: "event:name").queryEqual(toValue: searchString)
    print(query)
    query.observeSingleEvent(of: .value, with: { (snapshot) in
        guard let dictionary = snapshot.value as? [String: Any] else{
            print(snapshot.value)
            return
        }
        print(snapshot.value)
    }) { (err) in
        print("Failed to fetch event data", err)
    }

}

Returns this返回这个

(/events { ep = Made In America; i = "event:name"; sp = Made In America; })

It appears the question is看来问题是

"How can I query for a value contained in a child node?"

Given a structure similar to the original给定与原始结构相似的结构

"events" : {
  "CCDS" : {
    "attend:count" : 1,
    "event:imageURL" :"someURL",
    "event:name" : "Center City District Sips"
  "MIA" : {
    "attend:count" : 1,
    "event:imageURL" : "someURL",
    "event:name" : "Made In America"

a Firebase query would return the node you want. Firebase 查询将返回您想要的节点。

If the user typed in Made In America and tapped the search button here's the query to return that node in a snapshot.如果用户输入Made In America并点击搜索按钮,这里是在快照中返回该节点的查询。

let searchString = "Made In America"
let ref = self.ref.child("events")
let query = ref.queryOrdered(byChild: "event:name").queryEqualTo(searchString)
query.observeSingleEvent(of: .value, with: { (snapshot) in
    for child in snapshot.children {
        let snap = child as! DataSnapshot
        let eventDict = snap.value as! [String: Any]
        let attendCount = eventDict["attend:count"] as! String
        let url = eventDict["event:imageURL"} as! String
    }
})

If you want to do a partial string match, where the user could type in just a few characters like Made the code is similar but you need to let firebase return all of the matches starting with Made...如果你想进行部分字符串匹配,用户可以只输入几个字符,比如Made代码是相似的,但你需要让 firebase 返回所有以 Made 开头的匹配......

The query would look like this查询看起来像这样

let startString = "Made"
let endString = "Made" + "\\uf8ff"
let query = ref.queryOrdered(byChild: "event:name")
                        .queryStarting(atValue: startString)
                        .queryEnding(atValue: endString")

The "\" is a character at a very high code level in Unicode - because of that it encompasses all of the preceeding characters. "\" 是 Unicode 中非常高的代码级别的字符 - 因为它包含所有前面的字符。

However, querying 'on the fly' can create an unresponsive or sluggish UI so it's not recommended.但是,“即时”查询可能会导致用户界面无响应或缓慢,因此不建议这样做。

An alternative is to create a seperate node that contains a lot less info and contains the elements the user would search for and a reference to the event node.另一种方法是创建一个单独的节点,该节点包含的信息少得多,并且包含用户将搜索的元素和对事件节点的引用。

So the main node containing all the data looks like this所以包含所有数据的主节点看起来像这样

"events" : {
  "-uyuh8s8j8jsdas" : {
    "event": "CCDS"
    "attend:count" : 1,
    "event:imageURL" : "someURL",
  "-y88jsijsijjids" : {
    "event": "MIA"
    "attend:count" : 1,
    "event:imageURL" : "someURL",

and a 'smaller' node would look like this一个“较小”的节点看起来像这样

   events_for_searching
       -uyuh8s8j8jsdas
         event:name: "Center City District Sips"
       -y88jsijsijjids
         event:name: "Made In America"

With this, you could load all of the nodes from the events_for_searching into an array (then filter the array as the user types) which would make the UI very responsive and when the user selects a name, you can then use the key from that node as a reference to load the data from the events node via an observeSingleEvent function.有了这个,您可以将 events_for_searching 中的所有节点加载到一个数组中(然后根据用户类型过滤该数组),这将使 UI 非常敏感,并且当用户选择一个名称时,您可以使用该节点中的键作为通过observeSingleEvent 函数从事件节点加载数据的参考。

EDIT编辑

In response to a comment, I wanted to add a bit more detail in code.为了回应评论,我想在代码中添加更多细节。

Here's my structure这是我的结构

  "events" : {
    "event_0" : {
      "event:name" : "An Event"
    },
    "event_1" : {
      "event:name" : "Made In America"
    }
  },

and the code to query for event:name: Made In America以及查询 event:name: Made In America 的代码

let searchString = "Made In America"
let ref = self.ref.child("events")
let query = ref.queryOrdered(byChild: "event:name").queryEqual(toValue: searchString)

query.observeSingleEvent(of: .value, with: { (snapshot) in
    guard let dictionary = snapshot.value as? [String: Any] else{
        print(snapshot.value)
        return
    }
    print(snapshot.value)
}) { (err) in
    print("Failed to fetch event data", err)
}

and the output和输出

Optional({
    "event_1" =     {
        "event:name" = "Made In America";
    };
})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM