Turn Array with Key Values into JSON object in JavaScript - javascript

I have an array in JavaScript that I use JSON.stringify() on that ends up looking like this after:
[
{
"typeOfLoan":"Home"
},
{
"typeOfResidency":"Primary"
},
{
"downPayment":"5%"
},
{
"stage":"Just Looking"
},
{
"firstName":"Jared"
},
{
"lastName":"Example"
},
{
"email":"Jared#demo.com"
},
{
"cell":"8888888888"
},
{
"loanofficer":"Jim Loan"
}
]
I want the output to be a standard JSON object so that I can send it in a POST. Before this gets marked as duplicate, I have tried all of the answers I could possibly find already and they all end up not working or having syntax errors that I do not understand how to fix. This array is stored in variable jsonArray.

The array of objects, all with a single key, seems fishy. I suppose you want a single object literal with all the keys, which you can then send to you backend (and parse there). So first, reduce the many objects in a single one, then implement your ajax call to POST it to wherever. Here's how to reduce it:
let arr = [{"typeOfLoan":"Home"},{"typeOfResidency":"Primary"},{"downPayment":"5%"},{"stage":"Just Looking"},{"firstName":"Jared"},{"lastName":"Example"},{"email":"Jared#demo.com"},{"cell":"8888888888"},{"loanofficer":"Jim Loan"}];
let res = arr.reduce((a,b) => {
let key = Object.keys(b)[0];
a[key] = b[key];
return a;
}, {});
console.log(res);
Depending on what you use to send it to the backend, you might need to use JSON.stringify on res

Before stringifying, convert your request payload from an array to an object.
const arr = [{"typeOfLoan":"Home"},{"typeOfResidency":"Primary"},{"downPayment":"5%"},{"stage":"Just Looking"},{"firstName":"Jared"},{"lastName":"Example"},{"email":"Jared#demo.com"},{"cell":"8888888888"},{"loanofficer":"Jim Loan"}];
const payload = arr.reduce(function(acc, prev){
return Object.assign(acc, prev);
}, {});
console.log(payload);

Related

Alternative way to remove object from an array of json objects other than splice

I am still fairly new to JavaScript and I need help with an issue I am having.
I have a Java function that returns an array of json objects as such:
{
"payload": {
"phone": "1234567890",
"email": "test#test.com",
"contact": {
"personal": "test test",
"professional": "professionaltest test"
}
}
}
Now I have various scenarios in my API test where I am sending a POST request but purposefully missing some of the key/value pairs in the json. Such as:
Send the request by skipping contact.
Send the request by skipping phone.
etc.
I have researched and it seems that using .splice can be used to remove an object. However, from what I understand, the removal criteria is primarily driven by indexes (indices?). I'd rather not use remove by index in case something changes the output of the function in the future. Is there a way to remove by key name? Any alternative methods would be greatly appreciated too.
This is my favorite way to remove an value from an object.
For example, you want to remove phone from the payload object.
var { payload } = // your object
var { phone, ...newValue } = payload
console.log(newValue)
newValue is an copy of payload object without the phone key value.
function removeByKeys(obj, keys) {
return Object.keys(obj).reduce((newObj, key) => {
if (keys.includes(key)) {
return newObj;
}
return { ...newObj, [key]: obj[key] };
}, {});
}
const person = { name: 'bob', age: 36 };
removeByKeys(person, ['age']); // { name: 'bob' }
The has the same API as lodash omit. https://lodash.com/docs/4.17.15#omit. You can use that if you have more complicated use-cases, but the above is simple enough.

Finding value in json array and replacing it using Typscript [duplicate]

This question already has answers here:
Find object by id in an array of JavaScript objects
(36 answers)
Closed 2 years ago.
I have a file with 1000s of json rows like below. Im having difficulties locating a specific key in the array.
example json:
{"connection":"98374"
,"db":"8",
,"timestamp":"159905411631"
,"event":"DataCatch"
,"data":[{"key":"ruleid","value":"111"}
,{"key":"responseid","value":"155-response-4"}
,{"key":"responsetype","value":"Capture"}
,{"key":"reason","value":"ClientVisit"}
,{"key":"subreason","value":""}
,{"key":"score","value":"0.00"}
,{"key":"comment","value":""}]
}
I need to be able to find the "reason" key in the "data" array and replace the "value" with "test". The "data" array doesn't always appear on every json row, only when the "event" "dataCatch" is present.
I can parse it into a variable but I can only call the "data" array as a whole. Any ideas how to target specific values in an array?
Having a little trouble with this in Typescript.
There are any number of ways to go about this, but here's one.
First, parse your JSON into an array of objects.
Each element of the array will then look something like this:
{
connection: '98374',
db: '8',
timestamp: '159905411631'
event: 'DataCatch',
data: [
{ key: 'ruleid', value: '111' },
{ key: 'responseid', value: '155-response-4' },
{ key: 'responsetype', value: 'Capture' },
{ key: 'reason', value: 'ClientVisit' },
{ key: 'subreason', value: '' },
{ key: 'score', value: '0.00' },
{ key: 'comment', value: '' },
],
}
Let's call our array of objects allData, so we can refer to it later.
Now we can begin our "surgery".
We'll work from the inside-out, first looking at what needs to be done to a specific entry in an element's data array.
Here's a function that will do just what we need:
function updateReason(entry) {
if (entry.key === 'reason') {
return { ...entry, value: 'test' };
} else {
return entry;
}
}
This function checks if the provided entry has a key with a value of 'reason', and -- if so -- returns a new entry that is identical to the provided one except its value is 'test'.
How can we use this to update an entire data array (in an entry that has data, that is)?
We simply delegate the work to our dear friend map:
function updateData(data) {
// or simply `data.map(updateEntry);`
return data.map(entry => updateEntry(entry));
}
We're slowly working our way "outwards".
What about updating an entire entry in our big allData array (which may or may not contain data)?
// I've called such an entry a "collection", because I already used the name
// "entry" above :(
// A "collection" is just an entry in the big `allData` array.
function updateCollection(collection) {
if (collection.event === 'DataCatch') {
return {
...collection, // Leave everything else the way it is
data: updateData(collection.data), // But update the `data` array
};
} else {
return collection;
}
}
So close.
The last thing we need to do is apply this transformation to every element of our parsed allData array:
// or `allData.map(updateCollection);`
const updatedData = allData.map(collection => updateCollection(collection));
Also:
Q: Wouldn't it be cheaper to mutate the entry?
A: It would be cheaper, but not that much cheaper, due to a large amount of "structural sharing" that occurs here. I would recommend this approach unless you either need to mutate your input for some reason, or performance requirements demand it.
You need to map over the data key in your data variable like this.
data.data = data.data.map((item) => {
if (item.key === "reason") {
item.value = "test";
}
return item;
});
the data key is an array of values, so you need to loop through it and compare the value of the key property to the value you are looking for, if it matches then you can update the value property
https://codesandbox.io/s/angry-shirley-1gh83?file=/src/index.ts:666-782

convert a string to JSON object array- NOdejs

Lets presume I am sending a POST request to /api/products. My body is like below
{
"products":[
{
"id":"5f5065e44a12bd00232bcc6g",
"status":"true"
},
{
"id":"5f5065e44a12bd00232bcc6g",
"status":"true"
}
]
}
In my route I am trying to convert the above products to a JSON Object;
Below is my server code
const { products } = req.body;
console.log(JSON.parse(products));
but this gives me the error "message": "Something went wrong Unexpected token o in JSON at position 1"
How can i achieve this??
Cheers
Screenshots added
Tried below as well. But no luck
Nothing works.
const products = req.body;
console.dir(typeof products); // 'object'
console.dir(products); // { products: '[object Object]' }
const { products } = req.body;
console.dir(typeof products); // 'string'
console.dir(products); // '[object Object]'
postman developer console is as below. Doesnt seem to be an issue
{
"products":[
{
"id":"5f5065e44a12bd00232bcc6g",
"status":"true"
},
{
"id":"5f5065e44a12bd00232bcc6g",
"status":"true"
}
]
}
It's not a JSON object, JSON objects are surrounded by curly braces.
if you return
{"products": [ { "id":"5f5065e44a12bd00232bcc6g", "status":"true" }, { "id":"5f5065e44a12bd00232bcc6g", "status":"true" } ]}
then it will be worked.
The best thing to do would be to fix what you're sending to /api/products by putting {} around it, like this:
{
"products":[
{
"id":"5f5065e44a12bd00232bcc6g",
"status":"true"
},
{
"id":"5f5065e44a12bd00232bcc6g",
"status":"true"
}
]
}
Now it's valid JSON, and you can convert it via JSON.parse:
const obj = JSON.parse(req.body);
console.log(obj);
const { products } = obj;
or just
const { products } = JSON.parse(req.body);
Notice I'm using the entire body there. That will give you an object with a property (products) with the array of products. Alternatively, instead of parsing it manually, you could use middleware that would parse it automatically so that req.body is the parsed result, in which case it's just:
console.log(req.body);
const { products } = req.body;
If for some reason you can't send correct JSON, but it will always be in the form you've shown, you could add the {} afterward like this:
const obj = JSON.parse("{" + req.body + "}");
console.log(obj);
const { products } = obj;
or just
const { products } = JSON.parse("{" + req.body + "}");
but I strongly recommend not doing that, not least because you can't use middleware and sending malformed data around tends not to be ideal. Instead, send valid JSON in the first place.
Look at the content of your variable products, and your debugger.
In this line you're using an object destructuring assignment but the right hand side isn't an object, it's a string:
const { products } = req.body;
Try this instead:
const { products } = JSON.parse(req.body);
EDIT you appear to be using Express middleware or similar. There's a good chance that your object has already been converted from JSON so you just need your original line and not the JSON.parse line.
const { products } = req.body;
console.dir(products);
Figured it out.
Thanks to #T.j and #Alnitak was able to get this sorted. Used
let obj = req.body;
But i had an issue with my validator.
body('products')
.trim()
.not()
.isEmpty()
.withMessage('Custom product must have a main product'),
In the above code using .trim() converted the products into a string and once I removed the trim() it works perectly. Thanks all for the thoughts
Try with JSON.stringify()
Otherwise, maybe you were declaring an object (const { products }), try without the {}

Javascript - how to loop through dict inside a list

So I am pretty new when it comes to Javascript and it is as simple as read a json list with a value of:
{
"URL": [{
"https://testing.com/en/p/-12332423/": "999"
}, {
"https://testing.com/en/p/-123456/": "123"
},
{
"https://testing.com/en/p/-456436346/": "422"
}
]
}
What I would like to do is to have both the URL and the amount of numbers etc
"https://testing.com/en/p/-12332423/" and "999"
and I would like to for loop so it runs each "site" one by one so the first loop should be
"https://testing.com/en/p/-12332423/" and "999"
second loop should be:
"https://testing.com/en/p/-123456/" and "123"
and so on depending on whats inside the json basically.
So my question is how am I able to loop it so I can use those values for each loop?
As Adam Orlov pointed out in the coment, Object.entries() can be very useful here.
const URLobj = {
"URL": [{
"https://testing.com/en/p/-12332423/": "999"
}, {
"https://testing.com/en/p/-123456/": "123"
},
{
"https://testing.com/en/p/-456436346/": "422"
}
]
};
URLobj.URL.forEach(ob => {
console.log('ob', ob);
const entries = Object.entries(ob)[0]; // 0 just means the first key-value pair, but because each object has only one we can just use the first one
const url = entries[0];
const number = entries[1];
console.log('url', url);
console.log('number', number);
})
You mean something like this using Object.entries
const data = {
"URL": [
{"https://testing.com/en/p/-12332423/": "999"},
{"https://testing.com/en/p/-123456/": "123"},
{"https://testing.com/en/p/-456436346/": "422"}
]
}
data.URL.forEach(obj => { // loop
const [url, num] = Object.entries(obj)[0]; // grab the key and value from each entry - note the [0]
console.log("Url",url,"Number", num); // do something with them
})
let's call your object o1 for simplicity. So you can really go to town with this link - https://zellwk.com/blog/looping-through-js-objects/
or you can just use this code :
for(var i = 0; i < o1.URL.length; i++) {
//each entry
var site = Object.keys(URL[i]) [0];
var value = Object.values(URL[i]) [0];
// ... do whatever
}
don't forget each member of the array is an object (key : value) in its own right
You can extract the keys and their values into another object array using map
Then use the for loop on the newly created array. You can use this method on any object to separate their keys and values into another object array.
const data = {
"URL": [{
"https://testing.com/en/p/-12332423/": "999"
}, {
"https://testing.com/en/p/-123456/": "123"
},
{
"https://testing.com/en/p/-456436346/": "422"
}
]
}
var extracted = data.URL.map(e => ({
url: Object.keys(e)[0],
number: Object.values(e)[0]
}))
extracted.forEach((e) => console.log(e))

traversing js object properties adds quotes to strings in jade view

I'm using npm module traverse to filter data coming from mongodb / mongoose.
I might get this data:
[ { rating: 5,
title: { da: 'Web udvikling', en: 'Web Development' } },
{ rating: 5, title: { da: 'Node.js', en: 'Node.js' } } ]
'da' and 'en' indicates languages. I use traverse to filter mongoose data after current language like this:
var filtered = filterLanguage(lang, results);
// filter json obj by language
var filterLanguage = function(language, obj) {
return traverse(obj).map(function (item) {
if (this.key === language) {
this.parent.update(item);
}
});
};
I then show this in my template:
res.render('index', {
skills: filtered.skills
});
Finally I display it in the jade view:
ul.list-group
each skill, i in skills
if i < 5
li.list-group-item.sidebar-list-item= skill.title
Unfortunately it's displayed with quotes:
<ul>
<li>'Web Development'</li>
<li>'Node.js'</li>
</ul>
These quotes are not there in the unfiltered data (results.skill.title.da). So traverse is adding them. I used the module with 'plain' json and it's working perfectly.
The mongoose data seems plain and simple but of course there are a lot of properties on the prototype. Also traverse stalls if I don't omit '_id' (type bson/objectid) property from result set.
So traverse seems to have problems with mongoose data... Why is this? And how can I fix it?
-- EDIT --
I found a solution:
Before filtering I do this:
var json = JSON.parse(JSON.stringify(results));
var filtered = filterLanguage(lang, json);
This removes the quotes, but I'm not sure exactly what it does. Somehow converting the mongoose result to JSON? An explanation would be highly appreciated.
Fields in Mongoose documents are getters/setters, which seem to confuse either traverse or Jade/Pug.
The shortest method I found that seems to fix all of your issues is pretty ugly:
var filtered = filterLanguage(lang, results.map(r => JSON.parse(JSON.stringify(r))));
A more elaborate version:
var filtered = filterLanguage(lang, results.map(r => {
let j = r.toJSON()
j._id = j._id.toString()
return j;
}));
It would have been helpful to see what is the body of filterLanguage exactly or understand why it's called twice but as it stands, I don't think you need to use the traverse package at all.
A function such as below should do the trick and I even expanded it to work if the data is more tree-like and not as flat as represented in your example.
const reduceByLang = (data, lang) => {
// Look for a `lang` key in obj or
// if not found but still an object, recurse
const reduceByLangObj = (obj) => {
Object.keys(obj).forEach((key) => {
if (obj[key] === null) {
return;
}
if (obj[key][lang]) {
obj[key] = obj[key][lang]; // replace with desired lang
} else if (typeof obj[key] === 'object') {
reduceByLangObj(obj[key]); // recurse
}
});
return obj;
};
if (Array.isArray(data)) {
return data.map(reduceByLangObj);
} else {
return reduceByLangObj(data);
}
};
See example in JS Bin.
Also, if possible at all and if you do this type of selecting very often, I would look into saving the data in a different structure:
{ ratings: x, locales: { en: { title: 'Y' }, { da: { title: 'Z' } } } }
maybe, so that you can pick the selected language easily either in the query itself and/or in the controller.
EDIT: Checking for null.

Categories