如何查询自定义类型位置及表中距指定位置最近的地点?
查询自定义类型位置数据及就近地点
一、查询自定义类型的位置数据
不管用Amplify DataStore还是直接调用GraphQL API,都可以直接指定自定义类型内的字段来获取数据:
1. 使用DataStore查询
import { DataStore } from '@aws-amplify/datastore'; import { Post } from './models'; const fetchPostsWithLocation = async () => { const posts = await DataStore.query(Post); // 取出每个post的位置数据 posts.forEach(post => { console.log(`纬度: ${post.location.lat}, 经度: ${post.location.long}`); }); };
2. 使用GraphQL API查询
如果需要精准筛选字段,可直接编写GraphQL查询语句:
query GetPostsWithLocation { listPosts { items { id content location { lat long } } } }
二、查询距离指定位置最近的地点
Amplify默认查询不直接支持地理距离排序,可通过以下两种方案实现:
方案1:自定义GraphQL Resolver(推荐大数据量场景)
- 修改Schema添加自定义查询
在现有schema中新增接收目标经纬度的自定义查询:
a.schema({ Post: a.model({ location: a.customType({ lat: a.float(), long: a.float(), }), content: a.string(), }), // 新增就近查询接口 getNearbyPosts: a.query() .arguments({ targetLat: a.float(), targetLong: a.float(), maxDistance: a.float() // 可选:最大搜索距离(单位:千米) }) .returns(a.ref('Post').list()) .handler(a.handler.custom({ entry: 'getNearbyPosts.js' })), });
- 编写Resolver逻辑
在amplify/backend/api/[你的API名称]/resolvers/getNearbyPosts.js中实现距离计算与排序逻辑:
const { DynamoDB } = require('aws-sdk'); const docClient = new DynamoDB.DocumentClient(); // Haversine公式计算两点球面距离(千米) const haversineDistance = (lat1, lon1, lat2, lon2) => { const R = 6371; // 地球平均半径 const dLat = (lat2 - lat1) * Math.PI / 180; const dLon = (lon2 - lon1) * Math.PI / 180; const a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * Math.sin(dLon/2) * Math.sin(dLon/2); const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); return R * c; }; exports.handler = async (event) => { const { targetLat, targetLong, maxDistance = 10 } = event.arguments; const params = { TableName: process.env.Post_TABLE_NAME, }; const result = await docClient.scan(params).promise(); // 过滤范围内地点并按距离排序 const nearbyPosts = result.Items .filter(post => { const distance = haversineDistance(targetLat, targetLong, post.location.lat, post.location.long); return distance <= maxDistance; }) .sort((a, b) => { const distA = haversineDistance(targetLat, targetLong, a.location.lat, a.location.long); const distB = haversineDistance(targetLat, targetLong, b.location.lat, b.location.long); return distA - distB; }); return nearbyPosts; };
- 前端调用自定义查询
import { API } from '@aws-amplify/api'; const fetchNearbyPosts = async (lat, lon, maxDistance) => { const result = await API.graphql({ query: ` query GetNearbyPosts($targetLat: Float!, $targetLong: Float!, $maxDistance: Float) { getNearbyPosts(targetLat: $targetLat, targetLong: $targetLong, maxDistance: $maxDistance) { id content location { lat long } } } `, variables: { targetLat: lat, targetLong: lon, maxDistance } }); return result.data.getNearbyPosts; };
方案2:前端本地计算(小数据量场景)
如果数据量不大,可先获取所有数据,再在前端计算距离并排序:
import { DataStore } from '@aws-amplify/datastore'; import { Post } from './models'; const haversineDistance = (lat1, lon1, lat2, lon2) => { const R = 6371; const dLat = (lat2 - lat1) * Math.PI / 180; const dLon = (lon2 - lon1) * Math.PI / 180; const a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * Math.sin(dLon/2) * Math.sin(dLon/2); const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); return R * c; }; const fetchNearbyPostsLocally = async (targetLat, targetLong, maxDistance = 10) => { const allPosts = await DataStore.query(Post); return allPosts .map(post => ({ ...post, distance: haversineDistance(targetLat, targetLong, post.location.lat, post.location.long) })) .filter(post => post.distance <= maxDistance) .sort((a, b) => a.distance - b.distance); };
内容的提问来源于stack exchange,提问作者Michael Bahl
相关产品推荐
相关产品推荐

