I want to get the array of rooms and assign it to each property wrt their property_id, but the value returned is a pending promise. Not sure what's wrong. Although when I log the rooms
inside the then
it does log the value correctly. The result of console.log(property) is given below.
const vendorProfile = catchAsync(async (req, res, next) => {
await passport.authenticate("vendor-jwt", { session: false }, (err, user, info) => {
if (err) {
res.error = err || info.message;
return next(401);
}
if (!user) {
res.error = info.message;
return next(401);
}
return Promise.resolve(
getVendorProfileInfo(user._id)
.then((result) => {
if (result == "error") {
res.error = "Failed to fetch Vendor Profile";
next(500);
}
return getPropertyByVendorId(result._id).then((prop) => {
for (const property of prop) {
property._doc.property_rooms = getAllRooms(property._id).then((rooms) => rooms);
console.log(property);
}
res.message = "Vendor Profile fetched successfully";
res.data = {
vendor_info: result,
vendor_properties: prop,
};
return next(200);
});
})
.catch((err) => {
Logger.error(err);
res.error = "Failed to get vendor profile";
return next(500);
})
).catch((err) => {
Logger.error(err);
res.error = "Failed to get vendor profile";
return next(500);
});
})(req, res, next);
});
This is the function to get all the rooms for that property_id:
const getAllRooms = (propertyId) => {
return Promise.resolve(Room.find({ property_id: propertyId }).then((result) => result)).catch((err) => {
Logger.error(err);
return "error";
});
};
Here is my console.log(property)
:
{
property_basic_info: {
property_name: 'Welcome',
property_star_rating: 1,
property_booking_since: 2021,
property_channel_manager: ''
},
property_location: {
property_geo_loc: { coordinates: [Array], type: 'Point' },
property_locality: 'bhandup',
property_address: 'MAHAVIR UNIVERSE',
property_country: 'India',
property_state: 'Maharashtra',
property_city: 'Mumbai',
property_zip_code: '400078'
},
property_contact_details: { phone_no: '7059462868', email: '[email protected]' },
property_amenities: {
basic_facilities: [ 'Electricity', 'Air Conditioning', 'Elevator/ Lift', 'Bathroom' ],
general_services: [ 'Food', 'Bellboy service' ],
outdoor_activities_sports: [],
common_area: [],
food_drink: [],
health_wellness: [],
business_center_conference: [],
beauty_spa: [],
security: []
},
property_policies: {
checkin_time: '10:06',
checkout_time: '22:06',
cancellation_policy: 'Free cancellation upto 48 hrs'
},
property_rules: {
id_proof: {
acceptable_identity_proofs: 'Adhaar',
unacceptable_identity_proofs: 'Adhaar',
allow_same_id: true
},
guest_profile: [
[Object], [Object],
[Object], [Object],
[Object], [Object],
[Object]
],
general_safety_hygiene_guidelines: [],
room_safety_hygiene: [],
social_distancing: [],
food_drinks_hygiene: [],
property_restrictions: [],
pet_policy: [],
guest_suitabilty: [],
checkin_checkout_policy: [],
extra_bed_policy: [ [Object] ],
custom_policy: []
},
property_finance_legal: { gst_details: '29AAACR4849R2ZG' },
property_status: 1,
property_photo_id: [],
_id: 61607791b1af193c7b8b9f08,
vendor_id: 61607775b1af193c7b8b9f07,
createdAt: 2021-10-08T16:53:37.734Z,
updatedAt: 2021-10-08T16:53:37.734Z,
__v: 0,
property_rooms: Promise { <pending> }
}
Thanks in advance.
CodePudding user response:
That's because you are logging the promise outside the then
method.
The promise is resolved async so outside then
it is not resolved yet.
you have to change this line:
property._doc.property_rooms = getAllRooms(property._id).then((rooms) => rooms);
console.log(property);
to
property._doc.property_rooms = getAllRooms(property._id).then((rooms) => console.log(rooms));
or use async/await
to work with it like sync values
CodePudding user response:
I would suggest that you break your task into manageable, coherent sub-tasks. And "manageable" means "short", and "coherent" means "returning a promise".
First contender is passport.authenticate
. It's not returning a promise at all, it's a traditional callback-based function. We can convert it into a promise-based function like this:
passport.authenticateAsync = function (jwt, options) {
return new Promise( (resolve, reject) => {
this.authenticate(jwt, options, (err, user, info) => {
if (err) return reject(err);
if (!user) return reject(info.message);
resolve(user);
});
});
};
Now we can call that as passport.authenticateAsync("vendor-jwt", { session: false })
and get a promise that resolves to a user, or rejects.
Next up, getVendorProfileInfo
. Apparently this already returns a promise, but sometimes that promise's value can be "error"
, in which case it's actually an error. So let's wrap it in a promise that actually rejects when there is an error.
const getVendorProfileById = vendorId =>
getVendorProfileInfo(vendorId).then(profile => {
if (profile === "error") throw new Error("Failed to fetch Vendor Profile with ID " vendorId);
return profile;
}
);
Finally, there's getPropertyByVendorId
, which is your main point. You seem to want something that takes a vendor ID, and returns all rooms of all properties of that vendor. Promise#all
, Array#map
and getAllRooms
gets us a single promise that resolves with all rooms for a vendor, or rejects with an error:
const getRoomsByVendorId = vendorId =>
getPropertyByVendorId(vendorId).then(properties =>
Promise.all(properties.map(property => getAllRooms(property._id)))
);
And now it's straight-forward to wrap all that in a route handler:
const vendorProfile = async (req, res, next) => {
try {
const user = await passport.authenticateAsync("vendor-jwt", { session: false });
try {
res.data = {
vendor_info: await getVendorProfileById(user._id),
vendor_properties: await getRoomsByVendorId(user._id),
};
return next(200);
} catch (err) {
Logger.error(err);
return next(500);
}
} catch (err) {
res.error = err;
return next(401);
}
};