Why is the class creating an object with possibilities property undefined? - javascript

I'm trying to check an object (customer) against another object (developers), there are multiple developers so I have an object which houses all of them and I'm iterating through object that holds the developer, when a customer tests positive for the age condition then a test string is pushed onto the gateKeeper. possibilities property and in turn creates a new customer object from the customer class however, when I run gatekeeper.build(prospect, developers) pass it to a variable and console.log that variable it shows the possibilities properly as undefined, but when I console.log from inside the promise it shows it passed, for both developers, meaning it is pushing 'worked' onto the possibilities property but it isn't using that value when It builds the class, why?
edit
This now does as expected, I replaced the promise chain with a callback chain however as I understand it; the promise syntax paired with async await is the most correct way to execute functions when the timing of execution is important. I think I might be missing something as it regards to promises because code running within the promise chain executes but doesn't seem to affect anything outside the promise chain. If this is the case then (in my limited experience lol) I can't see any use case for the promises or the async await syntax, can someone please help me clarify this?
age: 28,
income: 75,
maritalStatus: 'Married',
majorCc: 'Y',
zipCode: 32805,
possibilities: {}
};
var developers = {
westgate: {
name: 'Westgate',
aTop: 68,
aBot: 28,
income: 50,
majorCc: 'Not Required',
maritalStatus: ['Married', 'Co Hab'],
payload: ['Myrtle Beach', 'Orlando', 'Gatlinburg', 'Cocoa Beach']
},
bluegreen: {
name: 'Bluegreen',
aTop: 999,
aBot: 25,
income: 50,
majorCc: 'Not Required',
maritalStatus: ['Married', 'Single Male', 'Co Hab', 'Single Female'],
payload: ['Myrtle Beach', 'Orlando', 'Gatlinburg', 'Cocoa Beach']
},
};
let gateKeeper = {
prospect: {},
settings: {},
possibilities: [],
methods: {
age(callback1) {
if (gateKeeper.prospect.age >= gateKeeper.settings.aBot && gateKeeper.prospect.age <= gateKeeper.settings.aTop) {
callback1();
}
},
income(callback) {
if (gateKeeper.prospect.income >= gateKeeper.settings.income) {
callback();
}
},
createPayload() {
var cache = {};
cache[gateKeeper.settings.name] = gateKeeper.settings.payload;
gateKeeper.possibilities.push(cache);
},
packageMethods() {
gateKeeper.methods.age(() => {
gateKeeper.methods.income(() => {
gateKeeper.methods.createPayload();
});
});
}
},
resources: class customer {
constructor(prospectInput, developerInput) {
this.age = prospectInput.age;
this.income = prospectInput.income;
this.maritalStatus = prospectInput.maritalStatus;
this.majorCc = prospectInput.majorCc;
this.zipCode = prospectInput.zipCode;
this.possibilities = developerInput; //MUST BE A DICTIONARY WITH ARRAY OF LOCATIONS
}
},
build(prospectInput, developersInput) {
var payload;
gateKeeper.prospect = prospectInput;
for (var i in developersInput) {
gateKeeper.settings = developersInput[i];
payload = gateKeeper.prospect;
gateKeeper.methods.packageMethods();
}
return new gateKeeper.resources(gateKeeper.prospect, gateKeeper.possibilities);
}
};
var test = gateKeeper.build(prospect, developers);
console.log(test.possibilities[1].Bluegreen[3]);

Related

Modify the data so that each of the rides, instead of having a `park_name` property, has an appropriate park_id

So wrote this function where it should take an array of object and modify one of the object name to its identical property id. This is the function i wrote:
function prepareRidesData(rides, parks) {
if (!rides.length) return [];
const parksLookup = {};
parks.forEach(({ park_id, park_name }) => {
parksLookup[park_name] = park_id;
});
const updatedRides = rides.map((ride) => {
ride.park_id = parksLookup[ride.park_name];
delete ride.park_name;
console.log(ride);
return ride;
})
return updatedRides;
}
I do some testing using this format:
test("Return two park name with id only", () => {
const input =([{
ride_name: "Tidal Wave",
year_opened: 2000,
park_name: "Thorpe Park",
votes: 1,
},
{
ride_name: 'Nemesis',
year_opened: 1994,
park_name: 'Alton Towers',
votes: 5,
}]);
const actual = prepareRidesData(input);
expect(actual).toEqual([ {
ride_name: "Tidal Wave",
year_opened: 2000,
park_id: 1,
votes: 1,
},
{
ride_name: "Nemesis",
year_opened: 1994,
park_id: 5,
votes: 1,
}]);
});
The error i'm getting is - TypeError: Cannot read properties of undefined (reading 'forEach')
Can someone help me identify where i am making the error for it not to be executing correctly.
It should change the park name to its identical park id
Your function definition has two parameters, rides and parks:
function prepareRidesData(rides, parks) {
But when you call it, you only pass one, input:
const actual = prepareRidesData(input);
So rides gets the value of input and parks is left undefined, hence the error. You need to pass the parks into the function as well as the rides.

What should the output of a JavaScript Class look like?

I am attempting to use inquirer to collect user input, that is turned into an object, it is then passed into a class constructor. Everything seems to working the way I want it to accept the resulting array of objects after they are passed though the classes come out in a way that is confusing me,
when I console.log the array that contains the objects that are returned by my classes this is what comes out:
[
Manager {
name: 'bob',
id: '24',
email: 'bob.com',
officeNumber: '1'
},
Engineer {
name: 'jack',
id: '347',
email: 'jack.com',
github: 'jackolantern'
},
Intern {
name: 'sally',
id: '987',
email: 'sally.com',
school: 'UCF'
}
]
Here is an example of one of the classes:
class Manager extends Employee {
constructor (employeeObj) {
super (employeeObj);
this.name = employeeObj.name;
this.id = employeeObj.id;
this.email = employeeObj.email;
this.officeNumber = employeeObj.officeNumber;
}
getOfficeNumber () {
return this.officeNumber;
}
getRoll () {
return "Manager";
}
}
module.exports = Manager;
and this is how the objects are passed into the classes:
const prompts = async () => {
let employeeObj = {};
const employee = await inquirer.prompt(addEmployee);
switch(employee.addEmployee){
case 'Manager':
employeeObj = await managerQuestions();
const manager = new Manager(employeeObj);
output.push(manager);
if(employeeObj.addAnother){
return prompts();
} else {
complete();
}
break;
case 'Engineer':
employeeObj = await engineerQuestions();
const engineer = new Engineer(employeeObj)
output.push(engineer)
if(employeeObj.addAnother){
return prompts();
} else {
complete();
}
break;
case 'Intern':
employeeObj = await internQuestions();
const intern = new Intern(employeeObj)
output.push(intern)
if(employeeObj.addAnother){
return prompts();
} else {
complete();
}
break;
default:
console.log('you have reached the default switch statement. thant should not happen. Please try again!');
}
}
what I cant seem to figure out, is why the "roll" for each object (Manager, Engineer, Intern) is being placed outside the corresponding object and not inside it. I was able to add a this.roll = "manager" inside the constructor and as expected it added in a property called roll with a value of "manager" which will work just fine for what I need to do, but how do I get rid of that Manager, Engineer, and Intern that shows up before each object in the output array, or can it be moved inside the object?
thank you for taking the time to read through all this.

How do I recursively search for results in Firestore?

I'm new to Node and Firebase.
I'm currently working on a crafting calculator for a game and have the game items stored in Firebase. Some items are composite items, for example:
1 Lumber Plank = 5 Logs
Based on such requirements, I've structured all the items as a single collection titled as items in Firebase.
Log would be persisted as:
{
"type": "basic",
"name": "log"
}
While lumber plank would be:
{
"type": "composite",
"name": "lumber plank",
"materials": ["log"],
"material_values": [5]
}
With such a structure, I'm trying to construct a crafting tree by recursively searching through the database. A final structure would look as such:
{
"name": "board",
"count": 1,
"materials": [
{
"name": "lumber plank",
"count": 1,
"materials": [
{
"name": "log",
"count": 5,
"materials": null
}
]
}
]
}
I'm having trouble with understanding the callbacks while debugging and this piece of code currently returns undefined followed by log (I'm assuming this comes from the console.log within the search function).
async function search(item, result, count) {
let calcItem = {
name: item,
count: count
};
db.collection("items")
.doc(item)
.get()
.then(doc => {
const data = doc.data();
if (data.type === basic) {
calcItem.materials = null;
result.push(calcItem);
return result;
} else {
let materials = data.materials;
let materialsCount = data.material_values;
calcItem.materials = [];
for (let i = 0; i < materials.length; i++) {
console.log(materials[i]);
search(materials[i], calcItem.materials, materialsCount[i]);
}
}
});
}
let item = "lumber plank";
search(item, [], 1).then(result => console.log(result));
Would appreciate any pointers/tips here. Thanks
Following feedback from Doug,
I've kinda refactored my code based on your comments and I'm seeing some progress.
function recursiveSearch(item, count, result) {
let calcItem = {
name: item,
count: count
};
dbSearch(item).then(function (doc) {
const data = doc.data();
console.log(data);
if (data.type === basic) {
calcItem.materials = null;
result.push(calcItem);
return result;
} else {
let materials = data.materials;
let materialsCount = data.material_values;
calcItem.materials = [];
for (let i = 0; i < materials.length; i++) {
recursiveSearch(materials[i], materialsCount[i], calcItem.materials);
}
}
});
}
function dbSearch(item) {
return Promise.resolve(db.collection("items")
.doc(item)
.get()
.then());
}
Log now outputs the search correctly.
{
material_values: [ 5 ],
materials: [ 'log' ],
name: 'lumber plank',
type: 'composite'
}
{
name: 'log',
type: 'basic'
}
However, if I understand it correctly, if I were to add in this line it's still going to return undefined, am I right?
console.log(recursiveSearch("lumber plank", 1, [])
If so, how do I actually log out the entire item structure whilst completing all the recursive searches?
Sorry if the question sounds kinda dumb. I primarily come from a Java background and dealing with promises/async/await is entirely new to me
You're not dealing with promises correctly. search doesn't actually return a "real" promise, but the caller is expecting it to do so. Since it's async, but doesn't return a value directly, it's actually returning is a promise that always resolves to undefined. It's also apparently intended to be a recursive function, which is making it harder to understand (did you mean to return the promise from the inner call to search?).
Minimally, you should start by making search return the promise chain that it establishes:
return db.collection("item")...get().then()
This will let you receive the value returned by the then callback.
I'll also point out that you're started to use async/await syntax, but never committed to using await to make this code more easy to read, which is a bit confusing.

Possible race condition with cursor when using Promise.all

In the project that I am working on, built using nodejs & mongo, there is a function that takes in a query and returns set of data based on limit & offset provided to it. Along with this data the function returns a total count stating all the matched objects present in the database. Below is the function:
// options carry the limit & offset values
// mongoQuery carries a mongo matching query
function findMany(query, options, collectionId) {
const cursor = getCursorForCollection(collectionId).find(query, options);
return Promise.all([findManyQuery(cursor), countMany(cursor)]);
}
Now the problem with this is sometime when I give a large limit size I get an error saying:
Uncaught exception: TypeError: Cannot read property '_killCursor' of undefined
At first I thought I might have to increase the pool size in order to fix this issue but after digging around a little bit more I was able to find out that the above code is resulting in a race condition. When I changed the code to:
function findMany(query, options, collectionId) {
const cursor = getCursorForCollection(collectionId).find(query, options);
return findManyQuery(cursor).then((dataSet) => {
return countMany(cursor).then((count)=> {
return Promise.resolve([dataSet, count]);
});
);
}
Everything started working perfectly fine. Now, from what I understand with regard to Promise.all was that it takes an array of promises and resolves them one after the other. If the promises are executed one after the other how can the Promise.all code result in race condition and the chaining of the promises don't result in that.
I am not able to wrap my head around it. Why is this happening?
Since I have very little information to work with, I made an assumption of what you want to achieve and came up with the following using Promise.all() just to demonstrate how you should use Promise.all (which will resolve the array of promises passed to it in no particular order. For this reason, there must be no dependency in any Promise on the order of execution of the Promises. Read more about it here).
// A simple function to sumulate findManyQuery for demo purposes
function findManyQuery(cursors) {
return new Promise((resolve, reject) => {
// Do your checks and run your code (for example)
if (cursors) {
resolve({ dataset: cursors });
} else {
reject({ error: 'No cursor in findManyQuery function' });
}
});
}
// A simple function to sumulate countMany for demo purposes
function countMany(cursors) {
return new Promise((resolve, reject) => {
// Do your checks and run your code (for example)
if (cursors) {
resolve({ count: cursors.length });
} else {
reject({ error: 'No cursor in countMany' });
}
});
}
// A simple function to sumulate getCursorForCollection for demo purposes
function getCursorForCollection(collectionId) {
/*
Simulating the returned cursor using an array of objects
and the Array filter function
*/
return [{
id: 1,
language: 'Javascript',
collectionId: 99
}, {
id: 2,
language: 'Dart',
collectionId: 100
},
{
id: 3,
language: 'Go',
collectionId: 100
}, {
id: 4,
language: 'Swift',
collectionId: 99
}, {
id: 5,
language: 'Kotlin',
collectionId: 101
},
{
id: 6,
language: 'Python',
collectionId: 100
}].filter((row) => row.collectionId === collectionId)
}
function findMany(query = { id: 1 }, options = [], collectionId = 0) {
/*
First I create a function to simulate the assumed use of
query and options parameters just for demo purposes
*/
const filterFunction = function (collectionDocument) {
return collectionDocument.collectionId === query.id && options.indexOf(collectionDocument.language) !== -1;
};
/*
Since I am working with arrays, I replaced find function
with filter function just for demo purposes
*/
const cursors = getCursorForCollection(collectionId).filter(filterFunction);
/*
Using Promise.all([]). NOTE: You should pass the result of the
findManyQuery() to countMany() if you want to get the total
count of the resulting dataset
*/
return Promise.all([findManyQuery(cursors), countMany(cursors)]);
}
// Consuming the findMany function with test parameters
const query = { id: 100 };
const collectionId = 100;
const options = ['Javascript', 'Python', 'Go'];
findMany(query, options, collectionId).then(result => {
console.log(result); // Result would be [ { dataset: [ [Object], [Object] ] }, { count: 2 } ]
}).catch((error) => {
console.log(error);
});
There are ways to write this function in a "pure" way for scalability and testing.
So here's your concern:
In the project that I am working on, built using nodejs & mongo, there is a function that takes in a query and returns set of data based on limit & offset provided to it. Along with this data the function returns a total count stating all the matched objects present in the database.
Note: You'll need to take care of edge case.
const Model = require('path/to/model');
function findManyUsingPromise(model, query = {}, offset = 0, limit = 10) {
return new Promise((resolve, reject) => {
model.find(query, (error, data) => {
if(error) {
reject(error);
}
resolve({
data,
total: data.length || 0
});
}).skip(offset).limit(limit);
});
}
// Call function
findManyUsingPromise(Model, {}, 0, 40).then((result) => {
// Do something with result {data: [object array], total: value }
}).catch((err) => {
// Do something with the error
});

Can't pass variable outside the scope of a Sequalize promise [duplicate]

This question already has answers here:
How to return value from an asynchronous callback function? [duplicate]
(3 answers)
Closed 7 years ago.
Here is a bit of code to demonstrate my issue.
'use strict';
module.exports = function(sequelize, DataTypes) {
var Game = sequelize.define('Game', { ... }, {
tableName: 'games',
instanceMethods: {
getState: function(userClass) {
var currentGame = this;
var gameState = {};
userClass.findOne({ where: { id: currentGame.challenger_user_id }}).then(
function(challengerUser) {
userClass.findOne({ where: { id: currentGame.recipient_user_id }}).then(
function(recipientUser) {
var turn;
if (currentGame.turn_symbol == 'X') {
turn = { user: challengerUser, symbol: 'X' };
} else {
turn = { user: recipientUser, symbol: 'O' };
}
gameState.game = currentGame;
gameState.turn = turn;
gameState.participants = [
{ user: challengerUser, symbol: 'X' },
{ user: recipientUser, symbol: 'O' }
];
console.log(gameState);
// Shows the object with the assigned values
}
);
}
);
console.log(gameState)
// Shows an empty object.
}
},
classMethods: { ... }
});
return Game;
};
In the getState function, we first declare an empty object named gameState.
We then find two users -- so we're now nested within two scopes -- and try to assign a value to our gameState variable.
When doing a console.log within the two nested scopes, the object is shown with all of the assigned values.
gameState is shown to be an empty object when doing a console.log outside of the two nested scopes (after assigning values).
Can someone help explain my error here?
Also, what is the correct term for these nested scopes -- are they promises?
Thanks!
Okay, I thought of a possible solution immediately after writing the question.
The reason why the console.log(gameState) at the end of the getState function returns null is because it runs asynchronous to the sequelize promises.
In other words, the server took .05 milliseconds to get to the last console.log(gameState), but the server took .15 milliseconds to get to where values are assigned to it.
^ Is that correct?

Categories

Resources