当用户登录我的应用程序时,我希望他们能够看到选定半径内的用户数。我打算开始在我的数据库中存储坐标,并遍历每条记录(〜50,000),并运行userCoordinates.distance(from:databaseCoordinateValue)。但是,在测试过程中,我发现此过程需要很长时间,并且不是可扩展的解决方案。您是否对如何快速查询定义范围内的数据库项有任何建议?
我正在使用:
数据库结构示例以及如何存储数据
database.collection("users").document((Auth.auth().currentUser?.uid)!).setData([
"available_tags" : ["milk", "honey"]]) { err in
if let err = err {
print("Error adding document: \(err)")
}
}
答案 0 :(得分:3)
看看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;
}
S2几何有很多找到覆盖单元的方法(即,您要查找哪个区域的值),因此绝对值得研究API并找到适合您的用例的匹配项。