$pages->findRaw() will be helpful here. It's hugely faster than $pages->find() and easier to work with than SQL queries.
You could do a couple of searches and connect the resulting data by repeater page ID. Example:
// Ensure PagePaths module is installed so that URL is available to findRaw()
$shop_data = $pages->findRaw("template=shop", ['title', 'url', 'locations'], ['nulls' => true, 'flat' => true]);
// Here you could also get other fields from the repeater pages as needed
$location_data = $pages->findRaw("template=repeater_locations, check_access=0", ['location'], ['nulls' => true, 'flat' => true]);
$shops = [];
// Loop over the shop data and get the lat/lng for each location, matching by repeater page ID
foreach($shop_data as $id => $item) {
$data = [
'title' => $item['title'],
'url' => $item['url'],
'locations' => [],
];
$location_ids = explode(',', $item['locations.data']);
foreach($location_ids as $location_id) {
if(!isset($location_data[$location_id])) continue;
$data['locations'][] = [
'lat' => $location_data[$location_id]['location.lat'],
'lng' => $location_data[$location_id]['location.lng'],
];
}
$shops[$id] = $data;
}
db($shops);