【问题标题】:Multiple Geofire queries and client-side filtering多个 Geofire 查询和客户端过滤
【发布时间】:2017-01-18 14:48:18
【问题描述】:

我这几天一直在参考这个 SO 帖子: Filtering results with Geofire + Firebase

我的问题是,对于我的 iOS 应用程序,我需要制作一个按凭据排序的附近用户的单一列表,例如:高级会员(最高且位于列表顶部)、捐赠者(仅次于高级)、会员(基本/最低)。

我在我的 Firebase 服务器中为 GeoFire 位置创建了 3 个条目,这些条目根据这些凭据拆分用户,因此需要运行 3 个查询来检索它们。

GeoFire* geoFirePremium = [[GeoFire alloc] initWithFirebaseRef:[[[FIRDatabase database] reference] child:@"geofire-premium-members"]];
GeoFire* geoFireDonator = [[GeoFire alloc] initWithFirebaseRef:[[[FIRDatabase database] reference] child:@"geofire-donator-members"]];
GeoFire* geoFireRegular = [[GeoFire alloc] initWithFirebaseRef:[[[FIRDatabase database] reference] child:@"geofire-regular-members"]];
NSMutableDictionary* query1Items = [[NSMutableDictionary alloc] init];
NSMutableDictionary* query2Items = [[NSMutableDictionary alloc] init];
NSMutableDictionary* query3Items = [[NSMutableDictionary alloc] init];

CLLocation* coord = [[CLLocation alloc] initWithLatitude:34.2499 longitude:-85.4399]; // Test location
long searchDistance = 8;
float mile2Kilo = 1.60934;
float kilo2mile = 0.62137;
GFCircleQuery* query1 = [geoFirePremium queryAtLocation:coord withRadius:(CGFloat)(searchDistance * mile2Kilo)]; // Miles to Kilometers
[query1 observeEventType:GFEventTypeKeyEntered withBlock:^(NSString* key, CLLocation* location)
{
    // Store results in query1Items
}];
GFCircleQuery* query2 = [geoFireDonator queryAtLocation:coord withRadius:(CGFloat)(searchDistance * mile2Kilo)];
[query2 observeEventType:GFEventTypeKeyEntered withBlock:^(NSString* key, CLLocation* location)
{
    // Store results in query2Items
}];
GFCircleQuery* query3 = [geoFireRegular queryAtLocation:coord withRadius:(CGFloat)(searchDistance * mile2Kilo)];
[query3 observeEventType:GFEventTypeKeyEntered withBlock:^(NSString* key, CLLocation* location)
{
    // Store results in query3Items
}];

我的想法是添加一些代码来识别所有 3 个查询何时完成,然后将它们合并到 1 个列表中。

NSMutableDictionary* mergedItems = [[NSMutableDictionary alloc] init];
// For example:  { query1Items[], query2Items[], query3Items[], ... }

[query1 observeReadyWithBlock:^{
    NSLog(@"Query 1 is finished");
    // Check for queries 2 & 3 completion
    // Perform merge if all are completed
}];
[query2 observeReadyWithBlock:^{
    NSLog(@"Query 2 is finished");
    // Check for queries 1 & 3 completion
    // Perform merge if all are completed
}];
[query3 observeReadyWithBlock:^{
    NSLog(@"Query 3 is finished");
    // Check for queries 1 & 2 completion
    // Perform merge if all are completed
}];

所有 Firebase/GeoFire 引用的 JSON 结构如下:

- geofire-premium-members
    - userid
        - g: geohash
        - l
            - 0: lat
            - 1: lon

- geofire-donator-members   //same format

- geofire-regular-members   //same format

- users
    - userid
        - …

像这样使用多个查询是一种好方法吗?将来我可能需要添加更多凭据,并且不知道我的方法是否可以很好地扩展。是否有更好的方法来实现我需要的可能只使用单个查询来代替?我非常感谢任何见解

【问题讨论】:

  • 我们大多数人发现解析代码比解析描述该代码的单词更容易。如果您对当前代码的结构有疑虑,请分享重现这些疑虑的最少代码。如果您随后还添加 JSON 结构的 sn-p(作为文本,请不要截图),您更有可能得到有用的答案。
  • @FrankvanPuffelen 谢谢,我已经更新了相关代码

标签: ios objective-c firebase firebase-realtime-database geofire


【解决方案1】:

你的概念没有错。虽然它可能过于复杂,因为有三个查询来返回相同类型的数据并在代码中组合数据并执行额外的查询以获取其他用户数据。

即代码中的三个查询返回一堆用户 id,然后您需要对其进行更多查询以(例如)查找各个用户名

只要用户节点中的所有成员都具有相同的结构,您就可以将它们放在一个节点中并使用子属性来指示他们是什么类型的用户

userid_0
    name: "some name"
    user_type: "regular"
userid_1
    name: "another name"
    user_type: "donator"

然后GeoFire查询返回指定半径内的所有用户。

假设无论如何都必须查找用户的姓名(例如),您将拥有用户节点中的其余数据,并且可以简单地读入它们,按 user_type(在代码中)排序并显示。

话虽如此,如果您确定要如何对它们进行排序,那么对结构进行简单的更改就可以轻松实现。

userid_0
    name: "some premium name"
    user_type: 0
userid_1
    name: "a donator name"
    user_type: 1
user_id_2
    name: "regular name"
    user_type: 2

其中 0 = 高级用户,1 = 捐赠者用户,2 是普通用户。

然后在代码中排序的时候,按照user_type排序,溢价会浮到顶部。

【讨论】:

  • 我知道这种类型的结构在哪里有用,但在大多数情况下,我至少会返回 1000 个结果。我想不惜一切代价避免客户端排序。多个查询似乎可以解决这个问题
  • @codeflow 1000 结果将是少量数据,因此没什么大不了的。此外,对 1000 个结果进行排序不会占用太多处理能力 - 话虽如此,为什么要在代码中排序?如果您愿意,Firebase 可以在检索数据时在查询中为您排序。你想按什么排序?此外,如果您想朝那个方向发展,您也可以轻松地对该结构执行多个查询。这个想法是它是非规范化的、可扩展的和可维护的,并且可以在代码中轻松实现。
  • 谢谢@Jay 我不知道我可以使用 Firebase 对 GeoFire 查询进行排序?我还没有真正看到如何做到这一点。到目前为止,它在代码中还不容易接近,尽管我会说我的数据是相当非规范化的
  • @codeflow GeoFire 建立在 Firebase 之上,但维护着它自己的神奇数据集,因此它的查询基于特定的结构,因此它与 Firebase 查询“不同”。您的问题中添加了更多数据(谢谢),我一开始就误读了它,所以改变了我的答案以更好地解决它。
  • 感谢您的建议。由于我最近意识到我的一个节点结构实际上需要与其他两个不同,因此仍然需要尝试一些变通方法。我现在至少有了一些方向感
猜你喜欢
  • 1970-01-01
  • 2021-06-01
  • 2018-05-12
  • 1970-01-01
  • 2021-05-17
  • 1970-01-01
  • 1970-01-01
  • 2016-07-12
  • 2014-09-18
相关资源
最近更新 更多