91 lines
2.3 KiB
JavaScript
91 lines
2.3 KiB
JavaScript
import express from "express";
|
|
import { User } from "../models/User.js";
|
|
|
|
const router = express.Router();
|
|
|
|
router.get("/:field", async (req, res) => {
|
|
const { field } = req.params;
|
|
const lat = parseFloat(req.query.lat);
|
|
const lon = parseFloat(req.query.lon);
|
|
if (isNaN(lat) || isNaN(lon)) {
|
|
return res.status(400).json({ error: "Must provide lat & lon" });
|
|
}
|
|
|
|
const rawRadius = parseFloat(req.query.radius);
|
|
const radiusKm = isNaN(rawRadius) || rawRadius < 0 ? 50 : rawRadius;
|
|
const maxDistance = radiusKm * 1000;
|
|
const page = Math.max(1, parseInt(req.query.page) || 1);
|
|
const limit = 6; // now 6 per page
|
|
const skip = (page - 1) * limit;
|
|
|
|
const sortBy = req.query.sortBy === "rate" ? "rate" : "distance";
|
|
const order = req.query.order === "desc" ? -1 : 1;
|
|
|
|
try {
|
|
// pipeline to get paged docs
|
|
const pipeline = [
|
|
{
|
|
$geoNear: {
|
|
near: { type: "Point", coordinates: [lon, lat] },
|
|
distanceField: "distanceMeters",
|
|
maxDistance,
|
|
spherical: true,
|
|
},
|
|
},
|
|
{
|
|
$match: {
|
|
"profile.field": field,
|
|
"profile.published": true,
|
|
},
|
|
},
|
|
{
|
|
$sort:
|
|
sortBy === "rate"
|
|
? { "profile.rate": order }
|
|
: { distanceMeters: order },
|
|
},
|
|
{ $skip: skip },
|
|
{ $limit: limit },
|
|
];
|
|
|
|
// pipeline to count total matching
|
|
const countPipeline = [
|
|
{
|
|
$geoNear: {
|
|
near: { type: "Point", coordinates: [lon, lat] },
|
|
distanceField: "distanceMeters",
|
|
maxDistance,
|
|
spherical: true,
|
|
},
|
|
},
|
|
{
|
|
$match: {
|
|
"profile.field": field,
|
|
"profile.published": true,
|
|
},
|
|
},
|
|
{ $count: "count" },
|
|
];
|
|
|
|
const [docs, countRes] = await Promise.all([
|
|
User.aggregate(pipeline),
|
|
User.aggregate(countPipeline),
|
|
]);
|
|
|
|
const total = countRes[0]?.count || 0;
|
|
const totalPages = Math.ceil(total / limit);
|
|
|
|
const pros = docs.map((u) => ({
|
|
_id: u._id,
|
|
profile: u.profile,
|
|
distanceKm: u.distanceMeters / 1000,
|
|
}));
|
|
|
|
return res.json({ pros, page, totalPages });
|
|
} catch (err) {
|
|
return res.status(500).json({ error: err.message });
|
|
}
|
|
});
|
|
|
|
export default router;
|