面试题答案
一键面试1. 创建索引
为了优化查询性能,我们需要在 location
和 历史位置轨迹
字段上创建地理空间索引。
// 在 location 字段上创建 2dsphere 索引
db.bikes.createIndex({ location: "2dsphere" });
// 在历史位置轨迹数组字段上创建 2dsphere 索引,假设历史位置轨迹字段名为 historyLocations
db.bikes.createIndex({ historyLocations: "2dsphere" });
2. 查询语句编写
要查询某个城市区域内(多边形区域)目前可用且过去1小时内移动距离超过1公里的单车,我们可以按以下步骤编写查询语句:
// 定义多边形区域,假设多边形区域的 GeoJSON 格式如下
const polygon = {
type: "Polygon",
coordinates: [
[
[lng1, lat1],
[lng2, lat2],
[lng3, lat3],
// 更多坐标点
[lng1, lat1]
]
]
};
// 计算1小时前的时间
const oneHourAgo = new Date(new Date().getTime() - 60 * 60 * 1000);
db.bikes.find({
status: "可用",
location: {
$geoWithin: {
$geometry: polygon
}
},
historyLocations: {
$elemMatch: {
timestamp: { $gte: oneHourAgo },
location: {
$near: {
$geometry: polygon,
$maxDistance: 1000 // 1公里,单位为米
}
}
}
}
});
3. 性能优化手段
- 复合索引:如果查询还涉及其他字段(例如
status
),可以考虑创建复合索引。例如:
db.bikes.createIndex({ status: 1, location: "2dsphere", historyLocations: "2dsphere" });
- 批量读取:如果查询结果集较大,可以使用批量读取方式,减少网络传输压力。例如在Node.js中:
const cursor = db.bikes.find({...查询条件... });
cursor.batchSize(100).forEach((doc) => {
// 处理文档
});
- 缓存:对于频繁查询的结果,可以使用缓存机制(如Redis),减少直接查询MongoDB的次数。
- 分片:如果数据量巨大,可以对MongoDB进行分片,将数据分布到多个服务器上,提高并发处理能力。
// 在分片集群中创建索引
sh.enableSharding("yourDatabase");
sh.shardCollection("yourDatabase.bikes", { location: "2dsphere" });
- 优化查询逻辑:确保查询语句尽可能简洁高效,避免不必要的嵌套和复杂逻辑。例如,尽量减少使用
$or
操作符,因为它可能会影响索引的使用效率。如果确实需要使用$or
,可以考虑对每个条件分别创建索引。