Promise pending even after its resolved - javascript

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: 'roy.srijan#outlook.com' },
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.

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

Related

Sails avoid action exit on exception in loop

An Action is calling the helper function inside the loop. If the helper function raise some error then it exits with a specific code queryFailed like follows:
helpers/a/execute.js
module.exports = {
friendlyName: '',
description: '',
inputs: {},
exits: {
queryError: {
description: 'Query error'
},
success: {
description: 'yayyy!! success!'
}
},
fn: async function ({ conditions }, exits) {
let records = [],
MYSQL_QUERY = `SELECT * FROM model WHERE COLUMN = $1`;
try {
records = await Model.getDatastore().sendNativeQuery(MYSQL_QUERY, [['true']]);
}
catch (error) {
return exits.queryFailed(error);
}
return exits.success(records);
}
};
I have an action as follows that calls the above mentioned helper function.
controllers/action.js:
module.exports = {
friendlyName: 'Action',
description: 'Performs some action',
inputs: {
param1: {
description: 'param 1',
type: 'string'
},
param2: {
description: 'param 2',
type: 'ref'
}
},
exits: {
invalid: {
description: 'Invalid request',
responseType: 'invalid',
statusCode: 400
},
unexpected: {
description: 'Unexpected error',
responseType: 'unexpected',
statusCode: 500
},
success: {
description: 'success',
statusCode: 200,
outputType: 'ref'
}
},
fn: async function (inputs, exits) {
// Helper Ids
const arr = ['a', 'b'];
let response = [];
for (const element of arr) {
try {
records = await sails.helpers[element].execute.with({
conditions: conditions
});
}
catch (err) {
if (err.code === 'queryError') {
LOGGER.error('Database Error', err);
return exits.unexpected();
}
return exits.unexpected();
}
response.push(records);
}
return exits.success(response);
}
};
The issue with this is in case of an invalid query the helper function exits with queryError code as follows:
return exits.queryFailed(error);
Assuming helper a is executed successfully, if there is an error in helper b then ideally the action should not exit itself. It should continue executing and show the error in the final response for that block.
Expected Response:
{
"rows": [
{
"value": {
"id": "a",
"data": {},
"meta": {},
}
},
{
"error": {
"name": "serverError",
"statusCode": 500,
"message": "Internal server error.",
"id": 2
}
},
Current Behaviour: It's catching the queryError in the action and doing an exit with the error response:
{
"trace": "",
"error": {
"name": "serverError",
"statusCode": 500,
"message": "Internal server error"
}
}
Thank you in advance!

Mongoose mixed Type object array, can findOneAndUpdate

I have a controller edit card which updates the fields of cardsArray object.
cardsArray is mixed type object as fileds of each card object is different so i am storing mixed.type
Althought pushing new card using addCard controller works perfectly
But when edit card controller is called, it gives type error
When edit Controlller is callled is gives following error:
TypeError: Cannot read properties of null (reading 'cardsArray')
// Schema
const userSchema = new mongoose.Schema(
{
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
cardsArray: [{ type: mongoose.Schema.Types.Mixed }],
}
);
//__Mongodb Data
{
"_id": {
"$oid": "63b43ab32fc8d3c100cafecc"
},
"name": "usern_name",
"email": "pr****#gmail.com",
"password": "$2b$12$3nwifHakrBu94BwLXAC4Nu16Kw0.xyW8vAIPTMSgY7cYttVklDIZq",
"cardsArray": [
{
"title": "some_title",
"category": "Bank",
"cardHolder": "some_name",
"cardNumber": "54545454",
"expiry": "23/01",
"cvv": "***",
"logoIndex": 72,
"isFavourite": false,
"_id": {
"$oid": "63b83cc77288d277ef359533"
}
}
],
"loginIdsArray": [],
"docsArray": [],
"activitiesArray": [],
"__v": 0
}
// Add Card Controller.js___
addCard: async (req, res) => {
console.log(req.body.data, req.body.user_id)
// console.log('obj_id', newObjectId)
req.body.data._id = newObjectId;
try {
const response = await UserDatabase.findOneAndUpdate(
{ _id: req.body.user_id },
{
$push: {
// cardsArray: req.body.data,
cardsArray: { $each: [req.body.data] },
},
},
{ returnOriginal: false }
);
res.status(200).send(response);
} catch (error) {
console.log(error)
res.status(404).json({ message: error.message });
}
},
// edit card controller.js
editCard: async (req, res) => {
const id = req.params.id;
const { category, title, cardHolder, cardNumber, expiry, cvv, logoIndex, isFavourite } = req.body;
console.log(req.params.id)
try {
const response = await UserDatabase.findOneAndUpdate(
{ _id: "63b43ab32fc8d3c100cafecc", 'cardsArray._id': "63b709fc69a1cfa6fccd645c" },
{
$set: {
"cardsArray.$.title": req.body.title,
"cardsArray.$.category": req.body.category,
"cardsArray.$.cardHolder": req.body.cardHolder,
"cardsArray.$.cardNumber": req.body.cardNumber,
"cardsArray.$.expiry": req.body.expiry,
"cardsArray.$.cvv": req.body.cvv,
"cardsArray.$.logoIndex": req.body.logoIndex,
"cardsArray.$.isFavourite": req.body.isFavourite
}
},
);
console.log(response)
res.status(201).json(response.cardsArray);
} catch (error) {
console.log(error)
res.status(404).json({ message: error.message });
}
}
it means that there is no data matching the following _id and cardsArray._id
i thinks so its fails to find the feild 'cardsArray._id',first try finding the value by just findOne
await UserDatabase.findOneAndUpdate(
{ _id: "63b43ab32fc8d3c100cafecc", 'cardsArray._id': "63b709fc69a1cfa6fccd645c" })
if your find doesn't work try below methord not sure but it may work you have to either find the id and loop through the cardsArray of use $in or $match
await UserDatabase.findOneAndUpdate(
{ _id: "63b43ab32fc8d3c100cafecc", 'cardsArray':{$in:[ {_id:"63b709fc69a1cfa6fccd645c" }]})

Using `mongoose transactions` when saving message in two collections in mongodb

If the student sends a message to the teacher, the message is saved in the teachers and students collections. The same situation is when a teacher sends a message to the student, they are also save in the two collections teachers and students. How can I apply mongoose transaction in the following code so that the message is saved in two collections.I don' want a situation that the message will be saved in one collection and in the other collection will not be saved due to an error. I am asking for help and clues
const express = require('express');
const mongoose = require('mongoose');
require('dotenv').config();
//const app = express();
// Connect to our Database and handle an bad connections
module.exports.db = mongoose
.createConnection(process.env.DATABASE, {
useNewUrlParser: true,
useFindAndModify: false,
useUnifiedTopology: true,
useCreateIndex: true
}
);
//controller
const db = require('./connection');
const session = db.startSession();
session.startTransaction();
module.exports.sendMessage = (req, res) => {
let {sender, receiver, msg, role} = req.body;
var hex = /[0-9A-Fa-f]{6}/g;
sender = (hex.test(sender))? mongoose.Types.ObjectId(sender) : sender;
receiver = (hex.test(receiver))? mongoose.Types.ObjectId(receiver) : receiver;
console.log(sender, receiver, msg, 'send');
if(role === 'tutor') {
let teacherMessage = new TeacherMessageSchema.TeacherMessageSchema({
contentInfo : {
msg : msg
},
sender : sender
})
let studentMessage = new TeacherMessageSchema.TeacherMessageSchema({
contentInfo : {
msg : msg
},
receiver : receiver
})
db.db.collection('teachers').findOneAndUpdate(
{ _id : receiver },
{ $push: { messages: teacherMessage } },
(err, updated) => {
console.log(updated, 'vvv');
updated.value.hashed_password = undefined;
updated.value.salt = undefined;
if(err) {
res.status(404).json(err);
}
if (updated) {
res.status(200).json(updated.value);
db.db.collection('students').findOneAndUpdate(
{ _id : sender },
{ $push: { messages: studentMessage } },
);
}
}, session(session)
)
}
if(role === 'student') {
let studentMessage = new StudentMessageSchema.StudentMessageSchema({
contentInfo : {
msg : msg
},
receiver : receiver
})
let teacherMessage = new TeacherMessageSchema.TeacherMessageSchema({
contentInfo : {
msg : msg
},
sender : sender
})
db.db.collection('students').findOneAndUpdate(
{ _id : sender },
{ $push: { messages: studentMessage } },
(err, updated) => {
console.log(updated, 'sss');
updated.value.hashed_password = undefined;
updated.value.salt = undefined;
if(err) {
res.status(404).json(err);
}
if (updated) {
res.json(updated.value);
db.db.collection('teachers').findOneAndUpdate(
{ _id : receiver },
{ $push: { messages: teacherMessage } },
)
}
},
), session(session)
}
}
Logged variable db
{
db: NativeConnection {
base: Mongoose {
connections: [Array],
models: [Object],
modelSchemas: [Object],
options: [Object],
_pluralize: [Function: pluralize],
plugins: [Array]
},
collections: {},
models: {},
config: { autoIndex: true },
replica: false,
options: null,
otherDbs: [],
relatedDbs: {},
states: [Object: null prototype] {
'0': 'disconnected',
'1': 'connected',
'2': 'connecting',
'3': 'disconnecting',
'99': 'uninitialized',
disconnected: 0,
connected: 1,
connecting: 2,
disconnecting: 3,
uninitialized: 99
},
_readyState: 1,
_closeCalled: false,
_hasOpened: true,
_listening: false,
_connectionOptions: {
useNewUrlParser: true,
useFindAndModify: false,
useUnifiedTopology: true,
useCreateIndex: true,
promiseLibrary: [Function: Promise]
},
client: MongoClient {
_events: [Object: null prototype] {},
_eventsCount: 0,
_maxListeners: undefined,
s: [Object],
topology: [ReplSet],
[Symbol(kCapture)]: false
},
name: null,
'$initialConnection': Promise { [Circular] },
db: Db {
_events: [Object: null prototype],
_eventsCount: 3,
_maxListeners: undefined,
s: [Object],
serverConfig: [Getter],
bufferMaxEntries: [Getter],
databaseName: [Getter],
[Symbol(kCapture)]: false
}
}
}
I have added in the code Anytime there is an error:
await session.abortTransaction();
Otherwise (happy path) commit the changes.
await session.commitTransaction();
Abort and commit are Promise base functions, so I have changed the functions where they were used as async.
const express = require('express');
const mongoose = require('mongoose');
require('dotenv').config();
//const app = express();
// Connect to our Database and handle an bad connections
module.exports.db = mongoose
.createConnection(process.env.DATABASE, {
useNewUrlParser: true,
useFindAndModify: false,
useUnifiedTopology: true,
useCreateIndex: true
}
);
//controller
const db = require('./connection');
module.exports.sendMessage = async (req, res) => {
const session = await db.startSession();
session.startTransaction();
let {sender, receiver, msg, role} = req.body;
var hex = /[0-9A-Fa-f]{6}/g;
sender = (hex.test(sender))? mongoose.Types.ObjectId(sender) : sender;
receiver = (hex.test(receiver))? mongoose.Types.ObjectId(receiver) : receiver;
console.log(sender, receiver, msg, 'send');
if(role === 'tutor') {
let teacherMessage = new TeacherMessageSchema.TeacherMessageSchema({
contentInfo : {
msg : msg
},
sender : sender
})
let studentMessage = new TeacherMessageSchema.TeacherMessageSchema({
contentInfo : {
msg : msg
},
receiver : receiver
})
db.db.collection('teachers').findOneAndUpdate(
{ _id : receiver },
{ $push: { messages: teacherMessage } },
async (err, updated) => {
console.log(updated, 'vvv');
updated.value.hashed_password = undefined;
updated.value.salt = undefined;
if(err) {
await session.abortTransaction();
res.status(404).json(err);
return
}
if (updated) {
res.status(200).json(updated.value);
db.db.collection('students').findOneAndUpdate(
{ _id : sender },
{ $push: { messages: studentMessage } },
);
}
}, session(session)
)
}
if(role === 'student') {
let studentMessage = new StudentMessageSchema.StudentMessageSchema({
contentInfo : {
msg : msg
},
receiver : receiver
})
let teacherMessage = new TeacherMessageSchema.TeacherMessageSchema({
contentInfo : {
msg : msg
},
sender : sender
})
db.db.collection('students').findOneAndUpdate(
{ _id : sender },
{ $push: { messages: studentMessage } },
async (err, updated) => {
console.log(updated, 'sss');
updated.value.hashed_password = undefined;
updated.value.salt = undefined;
if(err) {
await session.abortTransaction();
res.status(404).json(err);
return;
}
if (updated) {
res.json(updated.value);
db.db.collection('teachers').findOneAndUpdate(
{ _id : receiver },
{ $push: { messages: teacherMessage } },
)
}
},
session(session)
)
}
await session.commitTransaction();
}

Return Map Row NULL

I'm trying to map a json response from mysql query, but i receive ho response: data: NULL
This is my code:
const audience = rows.map((row) => {
db.query(CountAudiences, [row.campaign], function(err, count, fields) {
if (err) throw err;
console.log('Query result: ', count[0].audience);
return {
id: row.id,
title: row.title,
campaign: row.campaign,
action: row.action,
date: row.date,
audiences: count[0].audience
}
});
});
res.json({
count: rows.length,
data: audience
})
Response:
{
"count":1,
"data":[
null
]
}
Do you know how solve this?
Thanks :)
In your code as you are placing a query, so it is a Async hit. Try this
function getResponse(){
let rows = [{ id: 1, title: 5 }, { id: 2, title: "ggg" }]
const audience = rows.map(async (row) => {
return new Promise((resolve,reject)=> {
db.query(CountAudiences, [row.campaign], function (err, count, fields) {
if (err) throw err;
console.log('Query result: ', count[0].audience);
resolve( {
id: row.id,
title: row.title,
campaign: row.campaign,
action: row.action,
date: row.date,
audiences: count[0].audience
})
})
})
});
return Promise.all(audience)
}
getResponse().then((reponseData)=>{
res.json({
count: rows.length,
data: reponseData
})

sequelize validate multiple column [this.column got undefined]

hi guys I have some problems, why this.day_number and this.teacher_id is undefined?
'use strict'
module.exports = (sequelize, DataTypes) => {
const Teacher = sequelize.models.teachers
const TimeSlot = sequelize.define('time_slots', {
day: {
type: DataTypes.STRING,
validate: {
notEmpty: {
msg: 'Hari harus diisi.'
},
isIn: {
args: [['Senin', 'Selasa', 'Rabu', 'Kamis', 'Jumat', 'Sabtu', 'Minggu']],
msg: "Hari tidak tersedia."
}
}
},
day_number: {
type: DataTypes.TINYINT,
validate: {
notEmpty: {
msg: 'Urutan hari harus diisi.'
},
isInt: {
msg: 'Urutan hari harus berupa angka.'
},
isIn: {
args: [[0, 1, 2, 3, 4, 5, 6]],
msg: "Urutan hari tidak tersedia."
}
}
},
time: {
type: DataTypes.TIME,
validate: {
notEmpty: {
msg: 'Waktu mulai harus diisi.'
},
isExists: (value, next) => {
TimeSlot.findOne({
where: {
time: value,
day_number: this.day_number,
teacher_id: this.teacher_id
},
attributes: ['id']
})
.then((data) => {
if (data) {
return next('Waktu mengajar sudah digunakan.')
}
next()
})
.catch((err) => {
next(err)
})
}
}
},
teacher_id: {
type: DataTypes.STRING,
validate: {
notEmpty: {
msg: 'Guru belum dipilih.'
},
isExists: (value, next) => {
Teacher.findOne({
where: {
id: value
},
attributes: ['id']
})
.then((data) => {
if (!data) {
return next('Guru tidak tersedia.')
}
next()
})
.catch((err) => {
next(err)
})
}
}
}
}, {
timestamps: true,
freezeTableName: true,
updatedAt: 'updated_at',
createdAt: 'created_at'
})
TimeSlot.associate = (models) => {
TimeSlot.belongsTo(models.teachers, {
foreignKey: 'teacher_id',
onDelete: 'CASCADE',
as: 'teacher'
})
}
return TimeSlot
}
You're using arrow functions and arrow functions don't bind this.(MDN - Arrow functions)
Replace all arrow functions like the code below.
isExists(value, next) {
TimeSlot.findOne({
where: {
time: value,
day_number: this.day_number,
teacher_id: this.teacher_id
},
attributes: ['id']
})
.then((data) => {
if (data) {
return next('Waktu mengajar sudah digunakan.')
}
next()
})
.catch((err) => {
next(err)
})
}

Categories