查找最近的用户而无需遍历许多记录

0 firebase swift google-cloud-firestore

当用户登录我的应用程序时,我希望他们能够看到选定半径内的用户数量。我打算开始在我的数据库中存储坐标并遍历每条记录(~50,000),运行 userCoordinates.distance(from: databaseCoordinateValue)。但是,在测试过程中,我发现这个过程需要很长时间,并且不是一个可扩展的解决方案。您对如何在定义的半径内快速查询数据库项目有什么建议吗?

我在用:

  • 斯威夫特 4
  • Firebase(Firestore 测试版)
  • Xcode 10

数据库结构示例以及数据如何存储

 database.collection("users").document((Auth.auth().currentUser?.uid)!).setData([
                "available_tags" : ["milk", "honey"]]) { err in
                if let err = err {
                    print("Error adding document: \(err)")
                }
             }
Run Code Online (Sandbox Code Playgroud)

R. *_*ght 6

看看 s2 几何 - http://s2geometry.io/。基本概念是您将地球上的每个位置编码为 64 位 #,彼此靠近的位置是接近的 #。然后,您可以通过从该位置查找 +/- 某个 # 的任何内容来查找 x 距离内的位置。现在,实际的实现有点复杂,因此您最终需要创建多个“单元格”,即。范围内的最小值和最大值#。然后,您对每个单元格进行查找。(更多信息请访问http://s2geometry.io/devguide/examples/coverings。)

这是在 node.js / javascript 中执行此操作的示例。我在后端使用它,让前端在区域/区域中传递。

    const S2 = require("node-s2");

    static async getUsersInRegion(region) {
    // create a region
    const s2RegionRect = new S2.S2LatLngRect(
      new S2.S2LatLng(region.NECorner.latitude, region.NECorner.longitude),
      new S2.S2LatLng(region.SWCorner.latitude, region.SWCorner.longitude),
    );

    // find the cell that will cover the requested region
    const coveringCells = S2.getCoverSync(s2RegionRect, { max_cells: 4 });

    // query all the users in each covering region/range simultaneously/in parallel
    const coveringCellQueriesPromies = coveringCells.map(coveringCell => {
      const cellMaxID = coveringCell
        .id()
        .rangeMax()
        .id();
      const cellMinID = coveringCell
        .id()
        .rangeMin()
        .id();

      return firestore
        .collection("User")
        .where("geoHash", "<=", cellMaxID)
        .where("geoHash", ">=", cellMinID).
        get();
    });

    // wait for all the queries to return
    const userQueriesResult = await Promise.all(coveringCellQueriesPromies);

    // create a set of users in the region
    const users = [];

    // iterate through each cell and each user in it to find those in the range
    userQueriesResult.forEach(userInCoveringCellQueryResult => {
      userInCoveringCellQueryResult.forEach(userResult => {
        // create a cell id from the has
        const user = userResult.data();
        const s2CellId = new S2.S2CellId(user.geoHash.toString());
        // validate that the user is in the view region
        // since cells will have areas outside of the input region
        if (s2RegionRect.contains(s2CellId.toLatLng())) {
          user.id = userResult.id;
          users.push(user);
        }
      });
    });

    return users;
  }
Run Code Online (Sandbox Code Playgroud)

S2 几何有很多方法可以找到覆盖单元格(即您要查找值的区域),因此绝对值得查看 API 并为您的用例找到正确的匹配项。