Ваша основная проблема заключалась в том, что вы возвращали значение dispensaries
, не дожидаясь вначале каждого местоположения, которое будет извлечено, проанализировано, собрано и затем добавлено в массив dispensaries
.
Приведенный ниже код выполняется посредством правильного потока операций для объединения двух местоположений.
export const getDispensaries = functions.https.onRequest((req, res) => {
// STEP: Define reused database locations
const DISPENSARY_REF = admin.database().ref("/dispensary");
const LOCATION_REF = admin.database().ref("/location");
// STEP: Fetch list of dispensaries
DISPENSARY_REF.once("value")
.then(function (allDispensariesSnapshot) {
// STEP: Define array to store all tasks so they can be run in parallel
const dispensaryPromises: Promise<Dispensary>[] = [];
// DataSnapshot.forEach() is syncronous - so we can't use async/await syntax here
// STEP: Iterate over each dispensary in the database
allDispensariesSnapshot.forEach(function (dispensarySnapshot) {
// STEP: Extract dispensary data
// Ref: /dispensary/someDispensaryID
// Available Data: { locationID, name }
const dispensaryValues = dispensarySnapshot.val();
const { locationID, name } = dispensaryValues;
// Fetch location data & resolve with completed dispensary object
// STEP: Fetch needed data from other database locations
const currentDispensaryPromise = LOCATION_REF.child(locationID).once("value")
.then(function (locationSnapshot) {
// STEP: Extract data
// Ref: /location/someLocationID
// Available Data: { latitude, longitude }
const locationValues = locationSnapshot.val();
const { latitude, longitude } = locationValues;
// STEP: Assemble objects
const location: Location = new Location(latitude, longitude);
// STEP: Return the final object
return new Dispensary(name, location);
});
// STEP: Add this task to list of tasks
dispensaryPromises.push(currentDispensaryPromise);
});
// STEP: wait for all tasks
return Promise.all(dispensaryPromises);
})
.then(dispensaries => {
// Objects were retrieved successfully
// STEP: Return data to client
res.json(dispensaries);
})
.catch(error => {
// Something went wrong
// STEP: Log & return error to client
console.log(error); // log full error here
res.status(500).json({error: error.message}); // but only return error message to client
});
});
Если на более позднем этапе вам нужно выбрать более одного местоположения, вы обновите currentDispensaryPromise
до:
// Fetch other data & resolve with completed dispensary object
// STEP: Fetch needed data from other locations
const currentDispensaryPromise = Promise.all([
LOCATION_REF.child(locationID).once("value"),
USER_REF.child(ownerID).child('name').once("value") // with locations that have lots of data, fetch only what's needed
])
.then(([locationSnapshot, ownerNameSnapshot]) => {
// STEP: Extract data
// Ref: /location/someLocationID
// Available Data: { latitude, longitude }
const locationValues = locationSnapshot.val();
const { latitude, longitude } = locationValues;
// Ref: /user/someOwnerID/name (string)
const ownerName = ownerNameSnapshot.val();
// STEP: Assemble objects
const location: Location = new Location(latitude, longitude);
const owner: Owner = new Owner(ownerID, ownerName);
// STEP: Return the final object
return new Dispensary(name, location, owner);
});
Примечание: Если такое сочетание данных диспансера и местоположения используется чаще, чем нет, рассмотрите возможность объединения объектов вместе, а не их хранения отдельно.
Другие примечания
Нет необходимости использовать объекты для Dictionary
и Location
, достаточно просто указать форму объекта как тип.
type Dispensary = {
name: number;
location: Location;
}
type Location = {
latitude: number;
longitude: number;
}
const {name, locationID} = dispensarySnapshot.val();
const location = locationSnapshot.val() as Location;
return {name, location} as Dispensary;
Однако, если вы хотите сохранить их как объекты, вы можете сгладить ваши определения:
class Dispensary {
constructor(public name: string, public location: Location) {}
}
class Location {
constructor(public latitude: number, public longitude: number) {}
}