Add conditions to an object dynamically from an Array - javascript

I have an object like this, that needs to be sent to an API -
var data = {
field : "category"
value : "order"
}
Now, this API also needs some conditions needed to be sent as nested objects. Something like this -
var data ={
field : "category"
value : "order"
AND : {
field : "circuit"
value : "ninth"
OR : {
field : "second"
value : "abc",
//more conditions here possible //
}
}
So, basically, a condition is nested inside a condition.
EDIT:: Note - Each condition added into the conditions array has to be nested into the previous condition
Now, I have an array of conditions -
conditionsArray = [
{filter: "AND", field: "circuit", value: "ninth"},
{filter: "OR", field: "second", value: "abc"}
]
How do I add conditions to data object from this conditionsArray in the most optimal way?
var data = {
field : "category"
value : "order"
}
Thank you for your time.
EDIT: sorry, I forgot to add what I have tried so far -
I have been trying to just form an object but this is by no means a good solution.
const check = () => {
console.log(conditionsArray);
const data: any = { ...fieldValue };
conditionsArray.forEach((condition: any) => {
const { filter, name, value } = condition;
const { AND, OR, NOT } = data;
if (AND || OR || NOT) {
if (AND) {
data["AND"][filter] = { name, value };
}
if (OR) {
data["OR"][filter] = { name, value };
}
if (NOT) {
data["NOT"][filter] = { name, value };
}
} else {
data[filter] = { name, value };
}
});
console.log(data,"log data");
};

You could reduce the array and return the nested object for the next iteration.
const
data = { field: "category", value: "order" },
conditionsArray = [{ filter: "AND", field: "circuit", value: "ninth" }, { filter: "OR", field: "second", value: "abc" }];
conditionsArray.reduce((o, { filter, ...rest }) => o[filter] = rest, data);
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Using recursion :
function addConditions(data, conditions) {
if (conditions.length == 0) { return data; }
var topMostCondition = conditions[0];
var objectToAdd = { field : topMostCondition.field, value : topMostCondition.value };
data[topMostCondition.filter] = addConditions(objectToAdd, conditions.splice(1));
return data;
}

If your conditionsArray items should be added in the order of appearance to data, you may go recursive way like that:
const conditionsArray=[{filter:"AND",field:"circuit",value:"ninth"},{filter:"OR",field:"second",value:"abc"}],
data={field:"category",value:"order"},
makeATree = (o, list, branch) => {
if(!list.length) return o
const [condition, ...restOfConditions] = list,
{filter, ...rest} = condition
return makeATree(
{
...o,
...(
!branch ?
{[filter]: rest} :
{[branch]: {...o[branch], [filter]: rest}}
)
},
restOfConditions,
filter
)
}
console.log(makeATree(data, conditionsArray))
.as-console-wrapper{min-height:100%;}

Related

How to format currency symbol in Intl.NumberFormat?

In a JSON data, I've certain currency data values in the form as follows:
const currencyData = [
{
"₹": "INR"
},
{
"¥": "JPY"
},
{
"€": "EUR"
},
{
"£": "GBP"
}
];
I've created a function which accepts 2 parameters one for 'amount' and other for 'currency code', but, what could be done, when second parameter is "$" or "¥" i.e a currency symbol. My intention is to map the currency symbol with above JSON data and give the relevant output, like for e.g: "$" is passed then it should filter comparing with the above JSON data and pass "USD" output and then it can be passed in the below function
const currencyFormatterNew = (amount, currCode) => {
let currencyCode;
try {
if (currCode == "undefined" || currCode == "") {
currencyCode = "";
} else {
currencyCode = currCode;
return new Intl.NumberFormat("en-US", {
style: "currency",
currency: currencyCode,
minimumFractionDigits: 0
}).format(amount);
}
} catch (err) {
console.log(err);
}
};
The function is called as following: {currencyFormatterNew(10000, "JPY")}
What would be optimal solution to map the 'currency symbol' with above json data and then give required output which could be used in the function created?
Here is the codesandbox link: https://codesandbox.io/s/selection-and-operation-antd-4-17-0-alpha-0-forked-2sqzt
const getCurrencyCode = (code) => {
const k = currencyData.find(a => Object.keys(a) == code);
return Object.entries(k)[0][1];
}
you can try this.
If you want to you can change the last return statement as following
return Object.values(k); // it will return an array
After the JSON has been loaded, store the currencyData array into an object:
const currencyMap = Object.assign({}, ...currencyData)
Then you can just use property accessor [prop] to get the equivalent symbol. This will be better for performance since you don't need to call .find or similar every time your function is called because those functions does a loop.
const currencyData = [
{
"₹": "INR"
},
{
"¥": "JPY"
},
{
"€": "EUR"
},
{
"£": "GBP"
}
];
const currencyMap = Object.assign({}, ...currencyData)
console.log(currencyMap);
let symbol = '₹';
console.log(currencyMap[symbol]);

Super Efficient object unwrapping

I have a snapshot coming from Firebase that I want to turn into a JS class. I currently have a monster loop that is terrible in almost every way. Would anyone have an example of a better way to turn the raw json into this class?
My current method is very long (see section two). I would love to learn a fast more efficient method.
Class:
class SuggestedLocation {
country_slug
region_slug
slug
marker_type
typeInType
geometry
properties
type
id
constructor(country_slug, region_slug, slug, marker_type, typeInType, geometry, properties, type, id) {
this.country_slug = country_slug
this.region_slug = region_slug
this.slug = slug
this.marker_type = marker_type
this.typeInType = typeInType
this.geometry = geometry
this.properties = properties
this.type = type
this.id = id
}
}
Current unwrapping method:
static fromSnapshot(snapshot) {
let suggestedLocations = [new SuggestedLocation()]
if (snapshot.exists()) {
const value = snapshot.val()
const countrySlugs = Object.keys(value)
for (const country_slug of countrySlugs) {
const regionSlugs = Object.keys(value[country_slug])
for (const region_slug of regionSlugs) {
const slugs = Object.keys(value[country_slug][region_slug])
for (const slug of slugs) {
const markerTypes = Object.keys(value[country_slug][region_slug][slug])
for (const markerType of markerTypes) {
const accomAmenityTypes = Object.keys(value[country_slug][region_slug][slug][markerType])
for (const accomAmenityType in accomAmenityTypes) {
const typeInTypes = Object.keys(value[country_slug][region_slug][slug][markerType][accomAmenityType])
for (const typeInType of typeInTypes) {
const ids = Object.keys(value[country_slug][region_slug][slug][markerType][accomAmenityType][typeInType])
for (const id in ids) {
const geoJsonObject = value[country_slug][region_slug][slug][markerType][accomAmenityType][typeInType][id]
const properties = geoJsonObject["properties"]
const geometry = geoJsonObject["geometry"]
const type = geoJsonObject["type"]
suggestedLocations.push(new SuggestedLocation(country_slug, region_slug, slug, markerType, typeInType, geometry, properties, type, id))
}
}
}
}
}
}
}
}
return new SuggestedLocationsObject(suggestedLocations)
}
Example Json:
{
"united-kingdom" : {
"calderdale" : {
"rossendale-way" : {
"accommodations" : {
"Campground" : {
"zO3HxZVELbd" : {
"geometry" : {
"coordinates" : [ -2.1901328761018704, 53.65022995288969 ],
"type" : "Point"
},
"properties" : {
"marker-color" : "#6e875f",
"marker-size" : "medium",
"marker-symbol" : "lodging",
"name" : "",
"place_id" : "zO3HxZVELbd",
"plus_code" : ""
},
"type" : "Feature"
}
}
}
}
}
}
}
You will have to drill down your snapshot data any way, but you could use Object.entries instead of Object.keys, so you get the corresponding value in one go.
Also you could use map and flatMap to produce the array of SuggestedLocation instances without explicit push.
If the multiple assignments to this.* bother you, then you could consider changing the constructor signature so it takes an object instead of the individual values. Then you can use Object.assign to transfer those values in one go.
Finally, I don't really get why you want the array of SuggestedLocation instances to have an initial element with all undefined properties ([new SuggestedLocation()]). The only reason I can think of is for the case where snapshot.exists() is false... then you would have an array with this one entry. But when there is data, why would you have this dummy entry included?
Here is the code that expresses the above ideas (in plain JavaScript - not TypeScript):
class SuggestedLocationsObject extends Array {
constructor(arr) {
super();
Object.assign(this, arr);
}
}
class SuggestedLocation {
constructor(obj) {
Object.assign(this, obj);
}
}
function fromSnapshot(snapshot) {
return new SuggestedLocationsObject(
!snapshot.exists()
? [new SuggestedLocation()]
: Object.entries(snapshot.val()).flatMap(([country_slug, regionSlugs]) =>
Object.entries(regionSlugs).flatMap(([region_slug, slugs]) =>
Object.entries(slugs).flatMap(([slug, markerTypes]) =>
Object.entries(markerTypes).flatMap(([markerType, accomAmenityTypes]) =>
Object.entries(accomAmenityTypes).flatMap(([accomAmenityType, typeInTypes]) =>
Object.entries(typeInTypes).flatMap(([typeInType, ids]) =>
Object.entries(ids).map(([id, {properties, geometry, type}]) =>
new SuggestedLocation({country_slug, region_slug, slug, markerType, typeInType, geometry, properties, type, id})
)
)
)
)
)
)
)
);
}
let data = {
"united-kingdom" : {
"calderdale" : {
"rossendale-way" : {
"accommodations" : {
"Campground" : {
"zO3HxZVELbd" : {
"geometry" : {
"coordinates" : [ -2.1901328761018704, 53.65022995288969 ],
"type" : "Point"
},
"properties" : {
"marker-color" : "#6e875f",
"marker-size" : "medium",
"marker-symbol" : "lodging",
"name" : "",
"place_id" : "zO3HxZVELbd",
"plus_code" : ""
},
"type" : "Feature"
}
}
}
}
}
}
};
let snapshot = {
exists() { return true },
val() { return data }
}
let result = fromSnapshot(snapshot);
console.log(result);

JavaScript - Targeting an object value to create another variable

So I have an array which looks like this:
[
{ TransactionValues: '50.00' },
{ TransactionValues: '-77.43' },
{ TransactionValues: '-20.23' },
{ TransactionValues: '200.23' }
]
I am trying to find a way to target the monetary value and create a variable based on the sum of these. When I try to target the "50.00" for example I get "Undefined" and it's still an array.
I'm not exactly sure how I can target it specifically, is it possible? Any help would be appreciated
As per the comments here is the full code (be wary I'm still learning so it's not elegant):
var fs = require('fs');
var parse = require('csv-parse');
var transactionValues = []; //Need an array to hold transactions
var currentTrans = [];
var savingsTrans = [];
//constuctor for transactions
function addData (id, accountType, initiatorType, dateTime, transactions) {
var data = {
"AccountID" : id,
"AccountType" : accountType,
"InitiatorType" : initiatorType,
"DateTime" : dateTime,
"TransactionValues" : transactions
}
transactionValues.push(data); //should add a new line
}
function logTrans (accountType, transactions) {
if (accountType == "CURRENT") {
var cTrans = {
"TransactionValues" : transactions
}
currentTrans.push(cTrans);
}
else {
var sTrans = {
"TransactionValues" : transactions
}
savingsTrans.push(sTrans);
}
};
//parses the csv file, loops each row and adds it to the transactionValue array
var parser = parse({columns: true}, function (err, results) {
console.table(results);
for (const row of results) {
addData(row.AccountID, row.AccountType, row.InitiatorType, row.DateTime, row.TransactionValue );
logTrans(row.AccountType, row.TransactionValue);
}
console.log(transactionValues);
console.log(currentTrans);
console.log(savingsTrans);
});
fs.createReadStream(__dirname+'/testData/customer-1234567-ledger.csv').pipe(parser)
not completely following but at the end of the day you have an array like data below.
you can use filter to target the attribute you want.
you can use map to pull out just the values.
you can use reduce to sum them all up.
run the snippet below to see each step
const data = [
{ TransactionValues: '50.00', AccountType: 'CURRENT' },
{ TransactionValues: '-77.43', AccountType: null},
{ TransactionValues: '-20.23', AccountType: 'CURRENT' },
{ TransactionValues: '200.23', AccountType: null }
];
const CurrentTrans = data.filter((x) => x.AccountType === 'CURRENT');
const SavingTrans = data.filter((x) => x.AccountType !== 'CURRENT');
console.log('CurrentTrans');
console.log(CurrentTrans);
console.log('SavingTrans');
console.log(SavingTrans);
const CurrentTransValues = CurrentTrans.map((x) => parseFloat(x.TransactionValues));
const SavingTransValues = SavingTrans.map((x) => parseFloat(x.TransactionValues));
console.log('CurrentTransValues');
console.log(CurrentTransValues);
console.log('SavingTransValues');
console.log(SavingTransValues);
const TotalCurrentValues = CurrentTransValues.reduce((sum, x) => sum + x);
const TotalSavingValues = SavingTransValues.reduce((sum, x) => sum + x);
console.log('TotalCurrentValues');
console.log(TotalCurrentValues.toFixed(2));
console.log('TotalSavingValues');
console.log(TotalSavingValues.toFixed(2));
So I may have fixed it by using parseFloat in my addData and logTrans functions:
function addData (id, accountType, initiatorType, dateTime, transactions) {
var data = {
"AccountID" : id,
"AccountType" : accountType,
"InitiatorType" : initiatorType,
"DateTime" : dateTime,
"TransactionValues" : parseFloat(transactions)
}
transactionValues.push(data); //should add a new line
}
function logTrans (accountType, transactions) {
if (accountType == "CURRENT") {
var cTrans = parseFloat(transactions);
currentTrans.push(cTrans);
}
else {
var sTrans = parseFloat(transactions);
savingsTrans.push(sTrans);
}
};
Now that seems to of worked. So I can use the "Sum values of objects in array" as suggested before. Thank you everyone :)

How to check if two elements are in an object

I am trying to make a function that checks if a key ( a number ) exists in an object, and then if that element has a specific sub element. this is what I am doing
const blacklistedCities = {
[NATION_ID_USA]: [
'New York',
],
[NATION_ID_JAPAN]: [
'Tokio',
'Kyoto',
]
}
export function isBlacklistedCity(city, nationId) {
if(blacklistedCities.indexOf(nationId) !== -1 && blacklistedCities. ??WHAT SHOULD I PUT HERE??) {
return false;
}
return true;
}
NATION_ID_USA and NATION_ID_JAPAN are constants imported from another file
this function should return false when the element is found because I am using it from a filter() function somewhere else but I am open to any suggestion
thanks
I'd think of the input object as describing a much simpler array of scalar values that will be queried.
// Convert the input to a set containing [ 'nationId-cityId', ...]
//
const blacklistedCities = {
NATION_ID_USA: [
'New York',
],
NATION_ID_JAPAN: [
'Tokio',
'Kyoto',
]
}
const keys = Object.entries(blacklistedCities).reduce((acc, [nationId, cityIdArray]) => {
let nationIds = cityIdArray.map(cityId => `${nationId}-${cityId}`)
acc = acc.concat(nationIds)
return acc
}, [])
// keep this set around for queries
const queryMe = new Set(keys)
// and query with nation, key pair
function queryFor(nationId, cityId) {
return queryMe.has(`${nationId}-${cityId}`)
}
console.log(queryFor('NATION_ID_USA', 'New York')) // -> true
console.log(queryFor('NATION_ID_FRANCE', 'Paris')) // -> false
You can use the nation name as a property name to index directly into the object, and then use .includes() on the array (if present):
export function isBlacklistedCity(city, nationId) {
return (nationId in blacklistedCitites) && blacklistedCities[nationId].includes(city);
}
You can do something like this
const blacklistedCities = {
NATION_ID_USA: [
'New York',
],
NATION_ID_JAPAN: [
'Tokio',
'Kyoto',
]
}
function isBlacklistedCity(city, nationId) {
if(blacklistedCities[nationId] && blacklistedCities[nationId].length > 0 && blacklistedCities[nationId].find((cityInObj) => cityInObj==city)) {
return true;
} else {
return false;
}
}
console.log(isBlacklistedCity("Tokio", "NATION_ID_JAPAN"));

Merge X-numbers of JSON into one JavaScript Object

I have several Ajax-requests that retrieves data from the server...
I want to add them together, so I can use the data set later.
This is how one JSON-looks like:
{
"51" : { id:"51", name:"frank" },
"52" : { id:"52", name:"jonny" }
}
A second later there might come another one, with the exactly the same structure. How do I just "append" a new json into this to make a large object with the same structure..
EG: (append like this)
{
"51" : { id:"51", name:"frank" },
"52" : { id:"52", name:"jonny" },
"72" : { id:"72", name:"daniel"},
"73" : { id:"73", name:"lisa"},
"74" : { id:"74", name:"ida"},
"75" : { id:"75", name:"ali"}
}
Assuming that the ID will always be unique, you can do something like:
var buffer = {};
messageSource.on('message', function (msg) {
var msgKeys = Object.keys(msg); // Get the list of IDs
msgKeys.forEach(function (key) { // For each numeric key...
buffer[key] = msg[key]; // Copy the message
});
});
If you cannot guarantee unique IDs, you'll need some minor changes:
var buffer = {};
messageSource.on('message', function (msg) {
var msgKeys = Object.keys(msg);
msgKeys.forEach(function (key) {
buffer[key] = (buffer[key] || []).push(msg[key]); // Only change, append to list for that key
});
});
You should use Jquery $.merge:
var obj1 = {
"51" : { id:"51", name:"frank" },
"52" : { id:"52", name:"jonny" }
};
var obj2 = {
"72" : { id:"72", name:"daniel"},
"73" : { id:"73", name:"lisa"},
"74" : { id:"74", name:"ida"},
"75" : { id:"75", name:"ali"}
}
var result = $.extend(obj1, obj2);
Working exemple here

Categories

Resources