simplify unreadable nested if/else - javascript

I need to determine the status of a parent object based on 2 variables of each of its children. I came up with a working solution, but this includes a nested "if-else if-else". Needless to say, it doesn't look very elegant.
I was wondering if there is a way to simplify this. I have muddled around with some map/reduce code, but did not get to anything that is more elegant than the code below.
const parent = {
children: [{
connected: true,
online: true
},
{
connected: true,
online: true
}
]
}
// all online & all connected => connected
// all online & some connected => partially disconnected
// all online & none connected => disconnected
// some online => partially offline
// none online => offline
const onlineArr = parent.children.map(c => c.online);
const connectedArr = parent.children.map(c => c.connected);
let status;
if (!onlineArr.includes(true)) {
status = 'Offline';
} else if (!onlineArr.includes(false)) {
if (!connectedArr.includes(true)) {
status = 'Disconnected';
} else if (!connectedArr.includes(false)) {
status = 'Connected';
} else {
status = 'Partially disconnected';
}
} else {
status = 'Partially offline';
}
console.log(status);

I'd just extract the all/some/none check into a function:
const overAll = (array, key, value, /*results in */ all, some, none) =>
array.every(it => it[key] === value) ? all : (array.some(it => it[key] === value) ? some : none);
Then it is as easy as:
const status = (
overAll(parent.children, "online", true, undefined, "Partially offline", "Offline") ||
overAll(parent.children, "connected", true, "Connected", "Partially connected", "not connected")
);
But your if/else is already quite clean IMO :)

Related

Javascript Conditional return object

I used aws-sns to create one webhook. Two lambda functions are checked by this webhook. One of the lambda functions publishes 'orderId' and'startTime', while another publishes 'orderId' and 'roundName'. Both lambdas fire at different times. As a result, publishing can happen at two different times. One or both of the'startTime' and 'roundName' parameters may be undefined.
If 'roundName' exists, the 'updateOrder' variable will return 'roundName,' and the database will be updated. When'startTime' is set and 'roundName' is left blank, the 'roundName' will be rewritten from the database, which I don't want. Because if there is a 'roundName,' there will always be a 'roundName,' the value of 'roundName' can change but it will never be undefined.If startTime changes as well as roundName change then it will update the database. But my current logic is wrong. Struggling to implementing diffrent scenario logic.
const data = {
Records: [
{
Sns: {
Message:
'[{\n "orderId": "a4013438-926f-4fdc-8f6a-a7aa402b40ea",\n "roundName": "RO1"}]',
},
},
],
};
const existingData = [
{
modifiedAt: "2022-03-09T13:18:06.211Z",
lastMile: "progress",
createdAt: "2022-02-26T06:38:50.967+00:00",
orderId: "a4013438-926f-4fdc-8f6a-a7aa402b40ea",
},
];
// parse the data
const parseData = data.Records.flatMap((record) =>
JSON.parse(record.Sns.Message)
);
// check if the data exist or not
const existingOrder = existingData.filter(
(o1) => parseData.some((o2) => o1.orderId === o2.orderId)
);
// if there is no existingOrder then return false
if (existingOrder.length === 0) return;
// if there is exisiting order then add roundName and startTime from SNS event
const updateOrder = existingOrder.map((i) => {
const roundName = parseData.find((r) => {
return r.orderId === i.orderId;
}).roundName;
const startTime = parseData.find((r) => {
return r.orderId === i.orderId;
}).startTime;
return {
roundName: roundName ?? "",
startTime: startTime ?? "",
};
});
console.log(updateOrder);

Construct MongoDB query from GraphQL request

Let's say we query the server with this request, we only want to get the following user's Email, My current implementation requests the whole User object from the MongoDB, which I can imagine is extremely inefficient.
GQL
{
user(id:"34567345637456") {
email
}
}
How would you go about creating a MongoDB filter that would only return those Specified Fields? E.g,
JS object
{
"email": 1
}
My current server is running Node.js, Fastify and Mercurius
which I can imagine is extremely inefficient.
Doing this task is an advanced feature with many pitfalls. I would suggest starting building a simple extraction that read all the fields. This solution works and does not return any additional field to the client.
The pitfalls are:
nested queries
complex object composition
aliasing
multiple queries into one request
Here an example that does what you are looking for.
It manages aliasing and multiple queries.
const Fastify = require('fastify')
const mercurius = require('mercurius')
const app = Fastify({ logger: true })
const schema = `
type Query {
select: Foo
}
type Foo {
a: String
b: String
}
`
const resolvers = {
Query: {
select: async (parent, args, context, info) => {
const currentQueryName = info.path.key
// search the input query AST node
const selection = info.operation.selectionSet.selections.find(
(selection) => {
return (
selection.name.value === currentQueryName ||
selection.alias.value === currentQueryName
)
}
)
// grab the fields requested by the user
const project = selection.selectionSet.selections.map((selection) => {
return selection.name.value
})
// do the query using the projection
const result = {}
project.forEach((fieldName) => {
result[fieldName] = fieldName
})
return result
},
},
}
app.register(mercurius, {
schema,
resolvers,
graphiql: true,
})
app.listen(3000)
Call it using:
query {
one: select {
a
}
two: select {
a
aliasMe:b
}
}
Returns
{
"data": {
"one": {
"a": "a"
},
"two": {
"a": "a",
"aliasMe": "b"
}
}
}
Expanding from #Manuel Spigolon original answer, where he stated that one of the pitfalls of his implementation is that it doesn't work on nested queries and 'multiple queries into one request' which this implementation seeks to fix.
function formFilter(context:any) {
let filter:any = {};
let getValues = (selection:any, parentObj?:string[]) => {
//selection = labelSelection(selection);
selection.map((selection:any) => {
// Check if the parentObj is defined
if(parentObj)
// Merge the two objects
_.merge(filter, [...parentObj, null].reduceRight((obj, next) => {
if(next === null) return ({[selection.name?.value]: 1});
return ({[next]: obj});
}, {}));
// Check for a nested selection set
if(selection.selectionSet?.selections !== undefined){
// If the selection has a selection set, then we need to recurse
if(!parentObj) getValues(selection.selectionSet?.selections, [selection.name.value]);
// If the selection is nested
else getValues(selection.selectionSet?.selections, [...parentObj, selection.name.value]);
}
});
}
// Start the recursive function
getValues(context.operation.selectionSet.selections);
return filter;
}
Input
{
role(id: "61f1ccc79623d445bd2f677f") {
name
users {
user_name
_id
permissions {
roles
}
}
permissions
}
}
Output (JSON.stringify)
{
"role":{
"name":1,
"users":{
"user_name":1,
"_id":1,
"permissions":{
"roles":1
}
},
"permissions":1
}
}

Issues with geting results from filter inside filters

Guys i'm trying to filter some info from this array, a piece of it:
{
"entry": [
{
"ent_seq": 1000090,
"k_ele": [
{
"keb": "○"
},
{
"keb": "〇"
}
],
"r_ele": {
"reb": "まる"
},
"sense": [
{
"pos": "&n;",
"xref": "〇〇・まるまる・1",
"gloss": "symbol used as a placeholder (either because a number of other words could be used in that position, or because of censorship)"
},
{
"pos": "&n;",
"xref": "句点",
"gloss": [
"period",
"full stop"
]
},
{
"pos": "&n;",
"xref": "半濁点",
"gloss": [
"maru mark",
"semivoiced sound",
"p-sound"
]
}
]
},
Here we have the 'sense' item, where he can be an array or not, and inside of it the 'gloss' item, an array or not as well.
To do the main search, im doing this:
export const mainSearch = async (req, res) => {
var filterData2 = teste.entry.filter(x => {
if ('sense' in x && Array.isArray(x['sense'])) {
let result = x.sense.filter(sense_item => {
if (Array.isArray(x.sense['gloss'])) {
let result2 = sense_item.gloss.includes(req.params.id)
} else if (x.sense.gloss === req.params.id) return x
})
}
if(result) return x
}
)
if (filterData2) {
console.log(filterData2)
// res.json(filterData2)
}
Where i receive the search item from req.params.id, and i already tried dozens of things, im really stucked here, for the result right now i'm getting an empty array
The aim is if i get a true response for the search, to let the 'first filter' perceive it and go checking the rest.
For the 'k_ele' and 'r_ele' my code works fine too, a piece of it:
if ('k_ele' in x && Array.isArray(x['k_ele'])) {
let result = x.k_ele.some(el =>
el.keb.includes(req.params.id)
)
if (result) return x
} else
if ('k_ele' in x && x.k_ele.keb === req.params.id) return x
I'd suggest that you change your strategy. If the data is hard to filter and loop through, then it might be a good idea to change the data to something that is easier to work with.
In the end you'd want to check if the req.params.id is found in any of the gloss arrays or strings. Therefor it might be a good idea to collect all items in the gloss items into a single array and check if the queried value is found in any of the strings.
const data = [
"symbol used as a placeholder (either because a number of other words could be used in that position, or because of censorship)",
"period",
"full stop",
"maru mark",
"semivoiced sound",
"p-sound"
]
With the data like the example above, you'd only have to evaluate if the string you're looking for is present in the array.
const isFound = data.includes(value)
const teste={"entry":[{"ent_seq":1000090,"k_ele":[{"keb":"○"},{"keb":"〇"}],"r_ele":{"reb":"まる"},"sense":[{"pos":"&n;","xref":"〇〇・まるまる・1","gloss":"symbol used as a placeholder (either because a number of other words could be used in that position, or because of censorship)"},{"pos":"&n;","xref":"句点","gloss":["period","full stop"]},{"pos":"&n;","xref":"半濁点","gloss":["maru mark","semivoiced sound","p-sound"]}]}]};
// Example search request.
var req = {
params: {
id: 'full stop'
}
}
/**
* Check if the sense property is present and is an array.
* Then return an array of all sense objects.
*/
const senseEntries = teste.entry
.filter(entry => 'sense' in entry && Array.isArray(entry.sense))
.flatMap(({
sense
}) => sense)
/**
* Loop over the filtered sense objects and return
* either the gloss array or the gloss string inside of an array.
*/
const glossEntries = senseEntries
.flatMap(({
gloss
}) => Array.isArray(gloss) ? gloss : [gloss])
console.log(glossEntries);
/**
* Now all gloss items are collected in a single array and we can check if the id is found in any of the gloss strings.
*/
const isFound = glossEntries.includes(req.params.id)
console.log(`${req.params.id} in gloss values?`, isFound);
The person that posted an answer earlier gave me some clues, but he deleted it.
About the answer, the initial state of the logic was already too messy, and it was unable to return the true or false that the first 'filter' needed, that was the main problem.
So, i just started over focusing on the 'return' part and was there that things got better, anymore than that is just improvements to the code.
if ('sense' in x && !Array.isArray(x['sense'])) {
if (Array.isArray(x.sense['gloss'])) {
return x.sense.gloss.some(el => typeof(el) == 'string' && el.includes(req.params.id))
} else return typeof(x.sense.gloss) == 'string' && x.sense.gloss.includes(req.params.id)
} else if ('sense' in x && Array.isArray(x['sense'])) {
return x.sense.some((sense_item) => {
if (Array.isArray(sense_item['gloss'])) {
return sense_item.gloss.some(el => typeof(el) == 'string' && el.includes(req.params.id))
} else return typeof(sense_item.gloss) == 'string' && sense_item.gloss.includes(req.params.id)
})
}

How can I disable checkboxes and radio buttons from separate components?

Running into this ReactJS (with Redux) issue:
If premium white isn’t selected, gloss finish should be disabled. The radio button (premium) and checkbox (gloss) have separate methods in separate components – looks like they are both using state to send data.
Here’s the checkbox
buildCheckbox(item) {
return (
<Checkbox
key={item.key}
label={item.display}
name={item.key}
checked={this.props.order[item.key] || false}
onChange={checked => this.handleCheck(checked, item.key)}
disabled={item.disabled(this.props.order)}
/>
);
}
And the handleclick method used
handleCheck(checked, key) {
const { params, updateOrder } = this.props;
const { sessionId } = params;
// if doulbeSided option is removed, then clear the inside file.
if (key === 'doubleSided' && !checked) {
updateOrder(sessionId, { inside: null });
}
// set ink coverage based on printed flag
if (key === 'printed') {
const inkCoverage = checked ? 100 : 0;
updateOrder(sessionId, { inkCoverage });
}
// if unprinted, remove doublesided and gloss options
if (key === 'printed' && !checked) {
updateOrder(sessionId, { doubleSided: false });
updateOrder(sessionId, { gloss: false });
}
updateOrder(sessionId, { [key]: checked });
}
And the radio button’s method
onClick(id, ordAttribute) {
const { updateOrder, sessionId, validator } = this.props;
updateOrder(sessionId, { [ordAttribute]: id });
if (validator) validator(ordAttribute);
}
I saw that gloss has a service which is toggling disabled or not via the printed key on state here
gloss: {
display: 'Gloss Finish',
key: 'gloss',
component: 'checkbox',
disabled: state => !state.printed,
},
I’ve thought about creating a fourth radio button and just deleting the gloss option but I’m not sure where it’s being populated from – also thought about using a display none on the styles of the gloss that is activated via the radio button – but am not sure where to start.
just stated a new job and this is the previous employee's code - trying to figure it out. looks like the state is activated via this Action method:
export const updateOrder = (sessionId, payload) => (dispatch, getState) => {
dispatch(updateAction({ ...payload }));
const state = getState();
const ord = getNewOrderForm(state);
const minOrdValue = getMinOrdValue(state);
const { length, width, height, style, blankLength, blankWidth, qty, leadTime, sqFeet } = ord;
const priceMatrix = style ? getPriceMatrix(state)[style.priceMatrix] : null;
if (priceMatrix && style && style.calcPrice) {
dispatch(dispatchNewPrice(ord, style, priceMatrix, minOrdValue));
}
if (shouldCalcBlank({width, length, height}, style)) {
calcBlanks(style, {width, length, height})
.then(blanks => dispatch(updateAction(blanks)))
.catch(err => console.log('error', err))
}
if (blankLength && blankWidth && qty) {
calcSquareFeet({ blankLength, blankWidth, qty })
.then(sqFeet => {
dispatch(updateAction({ sqFeet }));
return sqFeet;
})
.then(sqFeet => sqFeet > 1000)
.then(lrgSqFeet => {
dispatch(updateAction({ lrgSqFeet }));
return lrgSqFeet;
})
.then(lrgSqFeet => {
if (lrgSqFeet && leadTime === 'rush') {
dispatch(updateAction({ leadTime: 'standard' }));
}
});
}
if (sqFeet && (!blankLength || !blankWidth || !qty)) {
dispatch(updateAction({ sqFeet: 0 }));
}
localStorage.setItem(sessionId, JSON.stringify(getNewOrderForm(getState())));
};
i thought about adding a the radio button has an id of 'clearwater' so i thought about adding a bool to this method that could then be accessed as clearwater: false (and when onClick is activated, updateOrder then changes it to clearwater: true, and then the gloss object in the service would then check disabled: state => !state.printed && !state.clearwater (this didn't work):
export const generateNewOrder = (userid, style, sessionId = uuid()) => dispatch => {
localStorage.setItem(
sessionId,
JSON.stringify({
userid,
style,
sessionId,
blindShip: true,
inkCoverage: '100',
printed: true,
})
);
history.push(`/order/new/${style.styleCode}/${sessionId}`);
dispatch(
newOrder({
userid,
style,
sessionId,
blindShip: true,
inkCoverage: '100',
printed: true,
})
);
if (style.type === 'static') {
const { dims, blankLength, blankWidth } = style;
const payload = {
...dims,
blankLength,
blankWidth,
};
dispatch(updateOrder(sessionId, payload));
}
};
I was hoping by changing the Service attached to the checkbox, I could add an additional condition that would cause the disabled functionality to be dependent on the state.boardStyle, but this doesn't seem to work (picture below isn't accurate, i changed it to boardStyle):
http://oi65.tinypic.com/wknzls.jpg
This is using redux -- kind of new to redux -- let me know if I'm missing any info -- I will post anything to get this solved.
Any help would be huge – thanks so much!
i think i figured it out . . .
there's probably a drier way to do this, but here goes:
first i created a new key [bool] (clearwater, set to false) on generateNewOrder method in Actions:
export const generateNewOrder = (userid, style, sessionId = uuid()) => dispatch => {
localStorage.setItem(
sessionId,
JSON.stringify({
userid,
style,
sessionId,
blindShip: true,
inkCoverage: '100',
printed: true,
clearwater: false,
})
);
history.push(`/order/new/${style.styleCode}/${sessionId}`);
dispatch(
newOrder({
userid,
style,
sessionId,
blindShip: true,
inkCoverage: '100',
printed: true,
clearwater: false
})
);
if (style.type === 'static') {
const { dims, blankLength, blankWidth } = style;
const payload = {
...dims,
blankLength,
blankWidth,
};
dispatch(updateOrder(sessionId, payload));
}
};
that gave me access to this state value, which i could then use in the onclick when the radio button was pressed. if the id was clearwater, the bool would be set to true, else it was set to false (only for the other two options because this code is used for other IDs)
onClick(id, ordAttribute) {
const { updateOrder, sessionId, validator } = this.props;
updateOrder(sessionId, { [ordAttribute]: id });
if (validator) validator(ordAttribute);
if (id === 'clearwater') {
updateOrder(sessionId, { clearwater: true });
} else if (id === 'kraft' || id === 'std_white_two_side'){
updateOrder(sessionId, { clearwater: false });
}
}
then all i needed to do was add this to the Service. if it was not printed !printed or not clearwater !clearwater, the checkbox would be disabled
const printing = {
doubleSided: {
display: 'Two Sided Print',
key: 'doubleSided',
component: 'checkbox',
disabled: state => !state.printed,
},
printed: {
display: 'Printed?',
key: 'printed',
component: 'checkbox',
disabled: () => false,
},
gloss: {
display: 'Gloss Finish',
key: 'gloss',
component: 'checkbox',
disabled: state => !state.printed || !state.clearwater,
},
};
I have a working example answering a similar problem, please, have a look. The whole logic is done in redux:
Want to uncheck the node of the tree structure in React JS

Acess node firebase and check value

I would like to access the node "status" and check: if false writes data, if true returns error alert.
I used the code:
var reference_value_of_counter = firebase.database().ref('contador/valor');
var reference_to_increment_counter = firebase.database().ref('contador/valor');
var reference_status_attendance = firebase.database().ref('agendamentos/primeiro-horario/status');
var reference_to_data_register = firebase.database().ref('agendamentos/primeiro-horario/');
if (reference_status_attendance.once('value', snap => snap.val() == false)) {
reference_value_of_counter.once('value', snap => reference_to_increment_counter.set(snap.val()+1));
reference_to_data_register.update({nome : 'isaac', sobrenome : "menezes", status: true});
}
else {
alert("sorry");
}
if (reference_status_attendance.once('value', snap => snap.val() == false))
This statement is not correct. once function wouldn't return the value that you return from your callback. You need to access the value and perform the if/else inside the callback. I haven't tested the below code but it should work or at least give you an idea of what needs to be done.
reference_status_attendance.once('value', snap => {
if(snap.val() == false) {
reference_value_of_counter.once('value', snap => reference_to_increment_counter.set(snap.val()+1));
reference_to_data_register.update({nome : 'isaac', sobrenome : "menezes", status: true});
}
else {
alert("sorry");
}
})
See Firebase Documentation
var reference_to_data_register = firebase.database().ref('agendamentos/primeiro-horario/');
reference_to_data_register.once('value')
.then(function(dataSnapshot) {
if(dataSnapshot.val().status){
//do this if status is true
} else {
// do this is status is false
}
});

Categories

Resources