I am trying to group arrays of addresses with the nearest and same location with max 4 people in a group from database input.
This is the code I am trying to use now:
export const sortRoute = async (data: z.infer<typeof sortRouteSchema>) => {
const validate = sortRouteSchema.safeParse(data);
if (!validate.success) return { success: false, error: "Invalid Field" };
const { staffs, organization_id, route_id } = validate.data;
// staffs variable is array of object like this and all address are for one country (Singapore)
[
{
"name": "Staff 17",
"address": "37 HOUGANG AVENUE 7 EVERGREEN PARK SINGAPORE 538803",
"place_id": "",
"department": "",
"postal_code": "538803"
},
{
"name": "Staff 16",
"address": "38 LORONG 5 TOA PAYOH EAST PAYOH SPRING SINGAPORE 310038",
"place_id": "",
"department": "",
"postal_code": "310038"
},
{
"name": "Staff 15",
"address": "467A YISHUN AVENUE 6 CASA SPRING @ YISHUN SINGAPORE 761467",
"place_id": "",
"department": "",
"postal_code": "761467"
},
{
"name": "Staff 14",
"address": "326 YISHUN RING ROAD YISHUN RIVERGREEN SINGAPORE 760326",
"place_id": "",
"department": "",
"postal_code": "760326"
},
{
"name": "Staff 13",
"address": "615 YISHUN RING ROAD SINGAPORE 760615",
"place_id": "",
"department": "",
"postal_code": "760615"
},
{
"name": "Staff 12",
"address": "476 SEMBAWANG DRIVE SINGAPORE 750476",
"place_id": "",
"department": "",
"postal_code": "750476"
},
{
"name": "Staff 11",
"address": "17 WOODLANDS AVENUE 9 REPUBLIC POLYTECHNIC (CAMPUS HEIGHTS) SINGAPORE 738968",
"place_id": "",
"department": "",
"postal_code": "738968"
},
{
"name": "Staff 10",
"address": "21 WOODLANDS CROSSING BLK A (WOODLANDS CHECKPOINT) SINGAPORE 738203",
"place_id": "",
"department": "",
"postal_code": "738203"
},
{
"name": "Staff 9",
"address": "21 WOODLANDS CROSSING BLK A (WOODLANDS CHECKPOINT) SINGAPORE 738203",
"place_id": "",
"department": "",
"postal_code": "738203"
},
{
"name": "Staff 8",
"address": "21 WOODLANDS CROSSING BLK A (WOODLANDS CHECKPOINT) SINGAPORE 738203",
"place_id": "",
"department": "",
"postal_code": "738203"
},
{
"name": "Staff 7",
"address": "17 WOODLANDS AVENUE 9 REPUBLIC POLYTECHNIC (CAMPUS HEIGHTS) SINGAPORE 738968",
"place_id": "",
"department": "",
"postal_code": "738968"
},
{
"name": "Staff 6",
"address": "27 WOODLANDS AVENUE 9 REPUBLIC POLYTECHNIC SINGAPORE 737909",
"place_id": "",
"department": "",
"postal_code": "737909"
},
{
"name": "Staff 5",
"address": "463 ANG MO KIO AVENUE 10 SINGAPORE 560463",
"place_id": "",
"department": "",
"postal_code": "560463"
},
{
"name": "Staff 4",
"address": "223A SERANGOON AVENUE 4 SINGAPORE 551223",
"place_id": "",
"department": "",
"postal_code": "551223"
},
{
"name": "Staff 3",
"address": "37 HOUGANG AVENUE 7 EVERGREEN PARK SINGAPORE 538803",
"place_id": "",
"department": "",
"postal_code": "538803"
},
{
"name": "Staff 2",
"address": "165 HOUGANG AVENUE 1 SINGAPORE 530165",
"place_id": "",
"department": "",
"postal_code": "530165"
},
{
"name": "Staff 1",
"address": "157 LORONG 1 TOA PAYOH PCF SPARKLETOTS PRESCHOOL @ TOA PAYOH CENTRAL BLK 157 (KN) SINGAPORE 310157",
"place_id": "",
"department": "",
"postal_code": "310157"
}
]
const geocodedAddresses: geocodedAddressesType[] = [];
const postalCodeBoundary: postalCodeBoundary[] = [];
const groupedAddresses: any = [];
const processedAddresses = new Set();
const promise = staffs.map(async (staff) => {
const { results } = await geoCodeByAddress(staff.address);
const location = results[0].geometry.location;
const address_comp = results[0].address_components;
const boundaries = [
{ lat: location.lat + 0.01, lng: location.lng + 0.01 },
{ lat: location.lat + 0.01, lng: location.lng - 0.01 },
{ lat: location.lat - 0.01, lng: location.lng - 0.01 },
{ lat: location.lat - 0.01, lng: location.lng + 0.01 },
{ lat: location.lat + 0.01, lng: location.lng + 0.01 },
];
geocodedAddresses.push({
...staff,
address: staff.address,
lat: location.lat,
lng: location.lng,
staff_name: staff.name as string,
});
postalCodeBoundary.push({
code: address_comp[address_comp.length - 1].long_name,
boundaries,
latLng: { lat: location.lat, lng: location.lng },
});
});
await Promise.all(promise);
geocodedAddresses.map((address) => {
postalCodeBoundary.map((postCode) => {
const latLng = new geometry.LatLng(address.lat, address.lng);
const inRange = geometry.computeDistanceBetween(latLng, postCode.latLng);
if (inRange <= 8000) {
if (postCode.code && !processedAddresses.has(address.staff_name)) {
if (!groupedAddresses[postCode.code]) {
groupedAddresses[postCode.code] = [];
}
groupedAddresses[postCode.code].push(address);
processedAddresses.add(address.staff_name);
}
}
});
});
const grouped_address = Object.values(groupedAddresses);
const empty: any = [];
grouped_address.map((address: any) => {
if (address.length > 4) {
empty.push(..._.chunk(address, 4));
} else {
empty.push(address);
}
});
const payload = empty.map((address: [], index: number) => ({
route_id,
organization_id,
staffs: address as Prisma.InputJsonValue,
}));
await db.routesGroup.createMany({
data: payload,
});
};
Current function seems ok but not give best group that should be like:
-
Not adding as first priority with same and nearest first
-
need to group all-together WOODLANDS address first in 4 people then rest will next group if existing group already reach to max people allow.
-
on recalculate result are not same
Any way to make more accurate and best grouping solution for this ?
Rakase Kumar is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.