firebase swift queries in 查询性能
firebase swift queries in queries performance
我是 Firebase 的新手,对 Swift 比较陌生。
我的 firebase 设置如下。我有用户、关注者和被屏蔽的用户。我负责 UITableViewCell class 中的关注者。
在我进一步讨论之前,我想知道:将观察者放入查询中的观察者中如何影响性能。 (希望这些是正确的术语)。下面是正确的方法吗?(最有效的方法)。它有效,但似乎也有点结结巴巴。感谢任何反馈。
{
"BlockedByUsers" : {
"ba1eb554-9a81-4a74-bfd9-484a32eee13d" : {
"97fee08f-19b2-4eb5-9eab-4b1985c22595" : true
}
},
"Dates" : {
"1457635040" : {
"97fee08f-19b2-4eb5-9eab-4b1985c22595" : true
},
},
"Locations" : {
"97fee08f-19b2-4eb5-9eab-4b1985c22595" : {
".priority" : "u14dkwm41h",
"g" : "u14dkwm41h",
"l" : [ 51.05521018175982, 3.720297470654139 ]
},
},
"Users" : {
"97fee08f-19b2-4eb5-9eab-4b1985c22595" : {
"blockedUsers" : {
"ba1eb554-9a81-4a74-bfd9-484a32eee13d" : true
},
"following" : {
"51879163-8b35-452b-9872-a8cb4c84a6ce" : true,
},
"fullname" : "",
"dates" : 1457635040,
"location" : "",
},
}
}
我的 Swift 代码包含我担心的多个查询:
var usersRef: Firebase!
var userFollowingRef: Firebase!
var blockedByUsersRef: Firebase!
var datesRef: Firebase!
var geofireEndRef: Firebase!
var geoFireEnd: GeoFire? {
return GeoFire(firebaseRef: geofireEndRef)
}
var dateRangeStart = Int()
var dateRangeEnd = Int()
override func viewDidLoad(){
super.viewDidLoad()
usersRef = DataService.ds.REF_USERS
userFollowingRef = DataService.ds.REF_CURRENTUSER_FOLLOWING
blockedByUsersRef = DataService.ds.REF_BLOCKED_BY_USERS
datesRef = DataService.ds.REF_DATES
geofireEndRef = DataService.ds.REF_GEOFIREREF_END
}
override func viewWillAppear(animated: Bool){
super.viewWillAppear(animated)
if userdefaultsUid != nil
{
geoFireEnd!.getLocationForKey(userID, withCallback: { (location, error) in
if (error != nil)
{
print("An error occurred getting the location for \(self.userID) : \(error.localizedDescription)")
} else if (location != nil)
{
self.updateUsersWithlocation(location)
} else
{
print("GeoFire does not contain a location for \(self.userID)")
self.updateUsersWithoutLocation()
}
})
}
}
func updateUsersWithlocation(location: CLLocation)
{
var allKeys = [String]()
let locationQuery = self.geoFireEnd!.queryAtLocation(location, withRadius: 100.0)
locationQuery.observeEventType(GFEventType.init(0), withBlock: {(key: String!, location: CLLocation!) in
allKeys.append(key)
self.datesRef.queryOrderedByKey().queryStartingAtValue(String(self.dateRangeStart)).queryEndingAtValue(String(self.dateRangeEnd)).observeEventType(.ChildAdded, withBlock: {
snapshot in
self.users.removeAll(keepCapacity: true)
self.newKeys.removeAll()
self.tableView.reloadData()
for datesKey in snapshot.children
{
self.usersRef.childByAppendingPath(datesKey.key!).observeSingleEventOfType(.Value, withBlock: { snapshot in
if let key = datesKey.key where key != self.userID
{
if allKeys.contains(key!) {
let newuser = FBUser(userKey: key!, dictionary: snapshot.value as! [String : AnyObject])
self.blockedByUsersRef.childByAppendingPath(key).childByAppendingPath(self.userID).observeSingleEventOfType(.Value, withBlock: { (snapshot) -> Void in
if let _ = snapshot.value as? NSNull
{
// we have not blocked this one
self.blockedByUsersRef.childByAppendingPath(self.userID).childByAppendingPath(key).observeSingleEventOfType(.Value, withBlock: { snapshot in
if let _ = snapshot.value as? NSNull
{
// we are not blocked by this one
if self.newKeys.contains(newuser.userKey) {}
else
{
self.users.append(newuser)
self.newKeys.append(newuser.userKey)
}
}
self.tableView.reloadData()
})
}
})
}
}
})
}
})
})
}
本质上,用户可以在特定日期出现在特定地点。他们记下了他们要去那里的日期,如下面的代码中所解释的。该日期可能与将要在该区域的其他用户重叠,时间范围为从前 7 天到后 21 天。这些用户可以被跟踪、屏蔽。但我正在让它们显示在 tableView 中。如果他们输入不同的日期或地点,则会弹出一组不同的用户。
if let userStartDate = beginningDate as? Double
{
let intUserStartDate = Int(userStartDate)
dateRangeStart = intUserStartDate - 604800
dateRangeEnd = intUserStartDate + 1814400
print(dateRangeStart, intUserStartDate, dateRangeEnd)
updateUsers()
}
else
{
updateUsersWithoutDate()
}
这可能根本不是答案或帮助,但我想把它扔在那里。
鉴于您真正想要寻找两件事:位置和时间,我们需要一些机制来处理它。
位置更静态;即保龄球盟友将永远是保龄球盟友,时代是动态的,我们需要一个范围。所以,给定一个结构
{
"events" : {
"event_0" : {
"loc_time" : "bowling_5"
},
"event_1" : {
"loc_time" : "tennis_7"
},
"event_2" : {
"loc_time" : "tennis_8"
},
"event_3" : {
"loc_time" : "dinner_9"
}
}
}
此结构处理这两个条件。您可以轻松查询在时间 7 有网球位置的所有节点。您还可以查询网球从开始时间 6 到结束时间 9 的范围,这将 return tennis_7 和tennis_8
这里有一些 ObjC 代码可以做到这一点
Firebase *ref = [self.myRootRef childByAppendingPath:@"events"];
FQuery *query = [[[ref queryOrderedByChild:@"loc_time"]
queryStartingAtValue:@"tennis_6"] queryEndingAtValue:@"tennis_8"];
[query observeEventType:FEventTypeChildAdded withBlock:^(FDataSnapshot *snapshot) {
NSLog(@"%@", snapshot);
}];
您可以由此推断,用您的位置代替位置和距离,或者用时间戳代替时间。
另一个修改(这可能是显而易见的,但为了清楚起见而说明)是使用对您的位置的引用而不是实际名称(保龄球、网球);即
events
"event_0" : {
"loc_time" : "-JAY8jk12998f_20160311140200" // locationRef_timestamp
},
locations
-JAY8jk12998f : {
"loc_name": "Fernando's Hideaway"
}
以想要获取数据的方式构建数据可以显着减少代码(以及查询中查询等的复杂性)。
希望对您有所帮助。
我是 Firebase 的新手,对 Swift 比较陌生。
我的 firebase 设置如下。我有用户、关注者和被屏蔽的用户。我负责 UITableViewCell class 中的关注者。 在我进一步讨论之前,我想知道:将观察者放入查询中的观察者中如何影响性能。 (希望这些是正确的术语)。下面是正确的方法吗?(最有效的方法)。它有效,但似乎也有点结结巴巴。感谢任何反馈。
{
"BlockedByUsers" : {
"ba1eb554-9a81-4a74-bfd9-484a32eee13d" : {
"97fee08f-19b2-4eb5-9eab-4b1985c22595" : true
}
},
"Dates" : {
"1457635040" : {
"97fee08f-19b2-4eb5-9eab-4b1985c22595" : true
},
},
"Locations" : {
"97fee08f-19b2-4eb5-9eab-4b1985c22595" : {
".priority" : "u14dkwm41h",
"g" : "u14dkwm41h",
"l" : [ 51.05521018175982, 3.720297470654139 ]
},
},
"Users" : {
"97fee08f-19b2-4eb5-9eab-4b1985c22595" : {
"blockedUsers" : {
"ba1eb554-9a81-4a74-bfd9-484a32eee13d" : true
},
"following" : {
"51879163-8b35-452b-9872-a8cb4c84a6ce" : true,
},
"fullname" : "",
"dates" : 1457635040,
"location" : "",
},
}
}
我的 Swift 代码包含我担心的多个查询:
var usersRef: Firebase!
var userFollowingRef: Firebase!
var blockedByUsersRef: Firebase!
var datesRef: Firebase!
var geofireEndRef: Firebase!
var geoFireEnd: GeoFire? {
return GeoFire(firebaseRef: geofireEndRef)
}
var dateRangeStart = Int()
var dateRangeEnd = Int()
override func viewDidLoad(){
super.viewDidLoad()
usersRef = DataService.ds.REF_USERS
userFollowingRef = DataService.ds.REF_CURRENTUSER_FOLLOWING
blockedByUsersRef = DataService.ds.REF_BLOCKED_BY_USERS
datesRef = DataService.ds.REF_DATES
geofireEndRef = DataService.ds.REF_GEOFIREREF_END
}
override func viewWillAppear(animated: Bool){
super.viewWillAppear(animated)
if userdefaultsUid != nil
{
geoFireEnd!.getLocationForKey(userID, withCallback: { (location, error) in
if (error != nil)
{
print("An error occurred getting the location for \(self.userID) : \(error.localizedDescription)")
} else if (location != nil)
{
self.updateUsersWithlocation(location)
} else
{
print("GeoFire does not contain a location for \(self.userID)")
self.updateUsersWithoutLocation()
}
})
}
}
func updateUsersWithlocation(location: CLLocation)
{
var allKeys = [String]()
let locationQuery = self.geoFireEnd!.queryAtLocation(location, withRadius: 100.0)
locationQuery.observeEventType(GFEventType.init(0), withBlock: {(key: String!, location: CLLocation!) in
allKeys.append(key)
self.datesRef.queryOrderedByKey().queryStartingAtValue(String(self.dateRangeStart)).queryEndingAtValue(String(self.dateRangeEnd)).observeEventType(.ChildAdded, withBlock: {
snapshot in
self.users.removeAll(keepCapacity: true)
self.newKeys.removeAll()
self.tableView.reloadData()
for datesKey in snapshot.children
{
self.usersRef.childByAppendingPath(datesKey.key!).observeSingleEventOfType(.Value, withBlock: { snapshot in
if let key = datesKey.key where key != self.userID
{
if allKeys.contains(key!) {
let newuser = FBUser(userKey: key!, dictionary: snapshot.value as! [String : AnyObject])
self.blockedByUsersRef.childByAppendingPath(key).childByAppendingPath(self.userID).observeSingleEventOfType(.Value, withBlock: { (snapshot) -> Void in
if let _ = snapshot.value as? NSNull
{
// we have not blocked this one
self.blockedByUsersRef.childByAppendingPath(self.userID).childByAppendingPath(key).observeSingleEventOfType(.Value, withBlock: { snapshot in
if let _ = snapshot.value as? NSNull
{
// we are not blocked by this one
if self.newKeys.contains(newuser.userKey) {}
else
{
self.users.append(newuser)
self.newKeys.append(newuser.userKey)
}
}
self.tableView.reloadData()
})
}
})
}
}
})
}
})
})
}
本质上,用户可以在特定日期出现在特定地点。他们记下了他们要去那里的日期,如下面的代码中所解释的。该日期可能与将要在该区域的其他用户重叠,时间范围为从前 7 天到后 21 天。这些用户可以被跟踪、屏蔽。但我正在让它们显示在 tableView 中。如果他们输入不同的日期或地点,则会弹出一组不同的用户。
if let userStartDate = beginningDate as? Double
{
let intUserStartDate = Int(userStartDate)
dateRangeStart = intUserStartDate - 604800
dateRangeEnd = intUserStartDate + 1814400
print(dateRangeStart, intUserStartDate, dateRangeEnd)
updateUsers()
}
else
{
updateUsersWithoutDate()
}
这可能根本不是答案或帮助,但我想把它扔在那里。
鉴于您真正想要寻找两件事:位置和时间,我们需要一些机制来处理它。
位置更静态;即保龄球盟友将永远是保龄球盟友,时代是动态的,我们需要一个范围。所以,给定一个结构
{
"events" : {
"event_0" : {
"loc_time" : "bowling_5"
},
"event_1" : {
"loc_time" : "tennis_7"
},
"event_2" : {
"loc_time" : "tennis_8"
},
"event_3" : {
"loc_time" : "dinner_9"
}
}
}
此结构处理这两个条件。您可以轻松查询在时间 7 有网球位置的所有节点。您还可以查询网球从开始时间 6 到结束时间 9 的范围,这将 return tennis_7 和tennis_8
这里有一些 ObjC 代码可以做到这一点
Firebase *ref = [self.myRootRef childByAppendingPath:@"events"];
FQuery *query = [[[ref queryOrderedByChild:@"loc_time"]
queryStartingAtValue:@"tennis_6"] queryEndingAtValue:@"tennis_8"];
[query observeEventType:FEventTypeChildAdded withBlock:^(FDataSnapshot *snapshot) {
NSLog(@"%@", snapshot);
}];
您可以由此推断,用您的位置代替位置和距离,或者用时间戳代替时间。
另一个修改(这可能是显而易见的,但为了清楚起见而说明)是使用对您的位置的引用而不是实际名称(保龄球、网球);即
events
"event_0" : {
"loc_time" : "-JAY8jk12998f_20160311140200" // locationRef_timestamp
},
locations
-JAY8jk12998f : {
"loc_name": "Fernando's Hideaway"
}
以想要获取数据的方式构建数据可以显着减少代码(以及查询中查询等的复杂性)。
希望对您有所帮助。