JSON array of object Convert - javascript

Here is my data array
let data = [{
"name": "s1",
"age": 20,
"address": "abc"
}, {
"name": "s2",
"age": 21,
"address": "def"
}];
i want to convert my data array into my filter array.
let filters = [
{
"field": "name",
"values": [{
"label": "s1",
"value": "s1"
}, {
"label": "s2",
"value": "s2"
}]
},
{
"field": "age",
"values": [{
"label": "21",
"value": "21"
}, {
"label": "20",
"value": "20"
}]
},
{
"field": "address",
"values": [{
"label": "abc",
"value": "abc"
}, {
"label": "def",
"value": "def"
}]
}
];

You could take a Map for collecting same field and their values. Then get the objects with the wanted items.
const
getValue = v => ({ label: v, value: v });
let data = [{ name: "s1", age: 20, address: "abc" }, { name: "s2", age: 21, address: "def" }],
filters = Array.from(
data.reduce((m, o) =>
Object
.entries(o)
.reduce((n, [k, v]) => n.set(k, [...(n.get(k) || []), getValue(v)]), m), new Map),
([field, values]) => ({ field, values })
);
console.log(filters);
.as-console-wrapper { max-height: 100% !important; top: 0; }

you'll need to extract the Object.keys of the first element or all of the elements if they may have different keys, then map throught the result to add the structure you want :
let data = [{
"name": "s1",
"age": 20,
"address": "abc"
}, {
"name": "s2",
"age": 21,
"address": "def"
}];
let fields = [...new Set(data.map(e => Object.keys(e)).flat())]; // extract the keys
// Or
/*
let fields = Object.keys(data[0]); // if you're sure that all the array entries have the same fields.
*/
let filters = fields.map(field => ({
field,
values: data.map(e => ({
label: e[field],
value: e[field]
}))
}))
console.log(filters)

First,define three Java DTOs,like this:
public class Data {
private String name;
private String age;
private String address;
// getter setter
}
public class Value {
private String label;
private String value;
}
public class Response {
private String field;
private List<Value> values;
}
Second,the main code:
public static void main(String[] args) throws Exception {
File file = new File("inputFileName");
TypeReference<List<Data>> reference = new TypeReference<List<Data>>() {
};
ObjectMapper mapper = new ObjectMapper();
List<Data> datas = mapper.readValue(file,reference);
JSONArray object = JSONArray.fromObject(datas);
Iterator iterator = object.iterator();
Map<String,List<Value>> var0 = new HashMap<>();
while (iterator.hasNext()) {
JSONObject jsonObject = (JSONObject) iterator.next();
Set<String> keys = jsonObject.keySet();
for(String key : keys) {
List<Value> values = var0.get(key);
if (null == values) {
values = new ArrayList<>();
values.add(new Value(jsonObject.getString(key),jsonObject.getString(key)));
var0.put(key,values);
} else {
values.add(new Value(jsonObject.getString(key),jsonObject.getString(key)));
}
}
}
List<Response> responses = new ArrayList<>(var0.size());
for(Map.Entry<String,List<Value>>entry:var0.entrySet()) {
Response response = new Response();
response.setField(entry.getKey());
response.setValues(entry.getValue());
responses.add(response);
}
File outPutFile = new File("outputFileName");
mapper.writeValue(outPutFile,responses);
}

Related

Group array of objects with a specific key value pushed first

Given the following Array of Objects:
[
{
"teamFK": 8650,
"code": "yellow_cards",
"typeId": 554,
"value": "5",
"side": "home"
},
{
"teamFK": 8650,
"code": "goals",
"typeId": 554,
"value": "1",
"side": "home"
},
{
"teamFK": 8990,
"code": "yellow_cards",
"typeId": 555,
"value": "2",
"side": "away"
},
{
"teamFK": 8990,
"code": "goals",
"typeId": 555,
"value": "0",
"side": "away"
}
]
I would like to group this data by code and get this result:
{
"stats": [
{
"name": "yellow_cards",
"stats": ["5","2"]
},
{
"name": "goals",
"stats": ["2","0"]
}
]
}
What I've done is the following which works but I want to make sure that the alway the stat with "side":"home" always pushed first into the array "stats": []:
const groupedStats = Object.entries(
query.reduce((acc, { typeId, value, code, side }) => {
if (!acc[code]) {
acc[code] = [];
}
acc[code].push(value);
return acc;
}, {}),
).map(([name, stats]) => ({ name, stats }));
My approach is sort it first by side using Array.sort() and then looping through the objects and adding it to stats
i created a const match to find if there is a match already so i dont have to add the name and value again basically if its not a match i'll add it to the stats array and if its a match then i'll just update the current index
const objs = [
{
teamFK: 8650,
code: "yellow_cards",
typeId: 554,
value: "5",
side: "home",
},
{
teamFK: 8650,
code: "goals",
typeId: 554,
value: "1",
side: "away",
},
{
teamFK: 8990,
code: "yellow_cards",
typeId: 555,
value: "2",
side: "away",
},
{
teamFK: 8990,
code: "goals",
typeId: 555,
value: "0",
side: "home",
},
];
let stats = [];
const transformedObj = objs
.sort((a, b) => {
if (a.side > b.side) {
return -1;
}
if (a.side < b.side) {
return 1;
}
return 0;
})
.forEach((obj) => {
const match = stats.find((stat) => stat.name === obj.code);
const statsIndex = stats.findIndex((stat) => stat.name === obj.code);
if (!match) {
stats = [...stats, { name: obj.code, value: [obj.value] }];
} else {
stats[statsIndex] = {
name: stats[statsIndex].name,
value: [...stats[statsIndex].value, obj.value],
};
}
});
console.log(stats);
You can sort array and use key grouping approach:
const data = [{"teamFK": 8650,"code": "yellow_cards","typeId": 554,"value": "5","side": "home"},{"teamFK": 8650,"code": "goals","typeId": 554,"value": "1","side": "home"},{"teamFK": 8990,"code": "yellow_cards","typeId": 555,"value": "2","side": "away"},{"teamFK": 8990,"code": "goals","typeId": 555,"value": "0","side": "away"}];
const groups = data
.sort(({ side: a }, { side: b }) => b.localeCompare(a))
.reduce((acc, { code, value }) => {
acc[code] ??= { name: code, stats: [] };
acc[code]['stats'].push(value);
return acc;
}, {});
const result = { stats: Object.values(groups) };
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0 }

moving a key value pair out of an array

I am trying to move everything in the Array Results outside and into the original object
this is the object
{
"Name": "John",
"Results": [
{
"Type": "DB",
"Immediate_Action": "No",
}
]
}
It should look like this
{
"Name": "John",
"Type": "DB",
"Immediate_Action": "No",
}
What I have so far is this
const mapOscarResults = ({ data }) => {
return data.map(entry => {
let mapped = {...entry};
entry.Results.forEach(key => {
let Type = mapped[key.Type]
if (mapped[key]) {
mapped[key].push(entry.Results[key]);
} else {
mapped[key] = [entry.Results[key]];
}
});
return mapped;
});
};
You can simply spread the Results array into an Object.assign() call.
const input = { "Name": "John", "Results": [{ "Type": "DB", "Immediate_Action": "No", }, { "Another": "value" }] };
const { Results, ...refactored } = input;
Object.assign(refactored, ...Results);
console.log(refactored)
This code works for your example:
const { Results: results, ...rest } = {
"Name": "John",
"Results": [
{
"Type": "DB",
"Immediate_Action": "No",
}
]
}
const res = {...rest, ...results.reduce((prev, curr) => ({
...prev,
...curr
}), {})}
console.log(res)
But I don't know what you expect when the Results array has more than one element.
In that condition, if this code does not fill your needs, ask me to change it.
however, it will join first Result with index 0, you can expand it
const data = {
"Name": "John",
"Results": [
{
"Type": "DB",
"Immediate_Action": "No",
}
]
}
const mapOscarResults = (data) => {
for (let i in Object.keys(data)){
if (Array.isArray(data[Object.keys(data)[i]])){
newKey = data[Object.keys(data)[i]][0]
data = {... data, ...newKey}
delete data[Object.keys(data)[i]]
}
}
return data
};
console.log(mapOscarResults(data))

javascript - validate nested json object

I have the following json schema.
const myJson = {
"type": "typeName"
"firstName": "Steven",
"lastName": "Smith",
"address": {
"primary": {
"city": "abc",
"street": {
"name": {
"subName": "someName"
}
}
}
}
}
And I want to loop over each of the properties for required validation on this json, I have the following code so far which works if the property in the json is not nested.
let errors = [];
const typeName = ['firstName', 'lastName'],
const typeAttr = Object.keys(myJson);
typeName.forEach(attr => {
if (!typeAttr.includes(attr)) {
errors.push(`Missing field: ${attr}`);
}
});
How can I add the nested json property like primary, city, street and validate the way I have done it.
Here's how you can check nested properties on json object
const myJson = {
type: "typeName",
firstName: "Steven",
lastName: "Smith",
address: {
primary: {
city: "abc",
street: {
name: {
subName: "someName",
},
},
},
},
};
let errors = [];
const typeName = ["firstName", "lastName", "address.primary", "address.primary.city"];
function checkNested(obj, level, ...rest) {
if (obj === undefined) return false;
if (rest.length == 0 && obj.hasOwnProperty(level)) return true;
return checkNested(obj[level], ...rest);
}
typeName.forEach((attr) => {
let props = attr.split(".");
if (!checkNested(myJson, ...props)) {
errors.push(`Missing field: ${attr}`);
}
});
console.log(errors);
For reference on how to check Nested properties you can check this answer.
Test for existence of nested JavaScript object key
I would do something like this. This method gives whether the data is having all the provided keys or not i.e., will return either true or false
let obj = {"type":"typeName","firstName":"Steven","lastName":"Smith","address":{"primary":{"city":"abc","street":{"name":{"subName":"someName"}}}}};
const typeName = ['firstName', 'lastName', 'address', 'address.primary', 'address.primary.city', 'address.primary.street'];
const validate = (data, types) => {
return types.every(type => {
// Split the keys using `.`
const keys = type.split('.');
// Check if the length is more than 1,
// if yes, then we need to check deeply
if (keys.length > 1) {
let datum = {
...data
};
// Check through all the keys found using split
for (let key of keys) {
// if any key is not found or falsy then return false
if (!datum[key]) {
return false;
}
datum = datum[key];
}
return true;
} else {
// if the length of the keys is not more than 1 then it means
// the key is at the top level and return the value as boolean
return !!data[type]
}
})
}
console.log(validate(obj, typeName));
console.log(validate(obj, ['firstName', 'lastName', 'address', 'address.primary', 'address.primary.zip']));
This below method will return the keys that were not present in the provided data
const validate = (data, types) => {
let errors = [];
types.forEach(type => {
const keys = type.split('.');
let datum = {
...data
};
// Loop through the keys
for (let [index, key] of keys.entries()) {
// Check if the key is not available in the data
// then push the corresponding key to the errors array
// and break the loop
if (!datum[key]) {
errors.push(keys.slice(0, index + 1).join('.'));
break;
}
datum = datum[key];
}
})
return errors;
}
const obj = {"type":"typeName","firstName":"Steven","lastName":"Smith","address":{"primary":{"city":"abc","street":{"name":{"subName":"someName"}}}}};
const typeName = ['firstName', 'lastName', 'address', 'address.primary', 'address.primary.city', 'address.primary.street'];
console.log(validate(obj, ['firstName', 'lastName']));
console.log(validate(obj, ['firstName', 'lastName', 'address', 'address.primary', 'address.primary.zip']));
console.log(validate(obj, [...typeName, 'test', 'address.primary.zip', 'address.test.zip']));
Use JSON Schema, a proposed IETF standard with tons of library implementations available for several languages for describing, generating, and validating JSON documents.
To require your JSON to have all the properties be present, you'll need a JSON Schema like below.
let typeNameSchema = {
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "https://example.com/typename.schema.json",
"title": "Type Name",
"description": "A person's name and address details",
"type": "object",
"required": [
"firstName",
"lastName",
"address"
],
"properties": {
"type": {
"type": "string"
},
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"address": {
"type": "object",
"required": [
"primary"
],
"properties": {
"primary": {
"type": "object",
"required": [
"city",
"street"
],
"properties": {
"city": {
"type": "string"
},
"street": {
"type": "object",
"required": [
"name"
],
"properties": {
"name": {
"type": "object",
"required": [
"subName"
],
"properties": {
"subName": {
"type": "string"
}
}
}
}
}
}
}
}
}
}
}
Then use any library to validate your JSON data against the above schema. jsonschema is one of the most popular JSON Schema validators for JavaScript. Here's how to validate your myJson data against the above typeNameSchema.
const Validator = require('jsonschema').Validator;
const validator = new Validator();
console.log(validator.validate(myJson, typeNameSchema)); // result
Validation results will be returned in a ValidatorResult object with the most important properties valid of type boolean and errors of type ValidationError[]. ValidationError object will have the property name and error message.

Build array from another array if some key are identical using JavaScript

I have an array of data. Some of the key in the array are same. I would like to create a new array based on the key and add the other data.
This is my array
var myObjOne = [
{
"name":"John",
"id":1,
"car":"maruti"
},
{
"name":"John",
"id":2,
"car":"wolks"
},
{
"name":"John",
"id":3,
"car":"bmw"
},
{
"name":"Peter",
"id":4,
"car":"alto"
},
{
"name":"Peter",
"id":5,
"car":"swift"
}
];
I would like to convert the array in to the below format.
var myObj = [
{
"name":"John",
"items": [
{ "id":1, "car":"maruti" },
{ "id":2, "car":"wolks" },
{ "id":3, "car":"bmw" }
]},
{
"name":"Peter",
"items": [
{ "id":4, "car":"alto" },
{ "id":5, "car":"swift" },
]
}
];
I am working on a node environment.
You can create an object using Array#reduce first which maps name with items, and then create the final array by looping over the intermediate map using a for...of loop:
var source = [{"name":"John","id":1,"car":"maruti"},{"name":"John","id":2,"car":"wolks"},{"name":"John","id":3,"car":"bmw"},{"name":"Peter","id":4,"cars":"alto"},{"name":"Peter","id":5,"cars":"swift"}];
const map = source.reduce((acc, {name, ...obj}) => {
if (!acc[name]) {
acc[name] = [];
}
acc[name].push(obj);
return acc;
}, {});
const result = [];
for (let[name, items] of Object.entries(map)) {
result.push({name, items});
}
console.log(result);
Array.reduce is at rescue.This method accepts an accumulator and current
item. Check in the accumulator if there exist an object where the value of name property is John or Peter
var myObjOne = [{
"name": "John",
"id": 1,
"car": "maruti"
},
{
"name": "John",
"id": 2,
"car": "wolks"
},
{
"name": "John",
"id": 3,
"car": "bmw"
},
{
"name": "Peter",
"id": 4,
"car": "alto"
},
{
"name": "Peter",
"id": 5,
"car": "swift"
}
];
var newObj = myObjOne.reduce(function(acc, curr, currIndex) {
// using findIndex to check if there exist an object
// where the value of the name property is John, Peter
// if it exist it will return the index else it will return -1
let ifNameExist = acc.findIndex(function(item) {
return item.name === curr.name;
})
// if -1 then create a object with name and item property and push
// it to the accumulator
if (ifNameExist === -1) {
let nameObj = {};
nameObj.name = curr.name;
nameObj.items = [];
nameObj.items.push({
id: curr.id,
car: curr.car
})
acc.push(nameObj)
} else {
// if such an object already exist then just update the item array
acc[ifNameExist].items.push({
id: curr.id,
car: curr.car
})
}
return acc;
}, []);
console.log(newObj)
Use .reduce to group by name, and use .find inside the reducer to find if the matching name has already been added:
const input=[{"name":"John","id":1,"car":"maruti"},{"name":"John","id":2,"car":"wolks"},{"name":"John","id":3,"car":"bmw"},{"name":"Peter","id":4,"cars":"alto"},{"name":"Peter","id":5,"cars":"swift"}]
const output = input.reduce((a, { name, ...item }) => {
const foundNameObj = a.find(nameObj => nameObj.name === name);
if (foundNameObj) foundNameObj.items.push(item);
else a.push({ name, items: [item] });
return a;
}, []);
console.log(output);

Push object keys and its values to array

I have an object like this:
{
"id": 23,
"name": "Jacob",
"link": {
"rel": "self",
"link": "www.abc.com"
},
"company":{
"data":{
"id": 1,
"ref": 324
}
}
I want to store each key with its value to an array in javascript or typescript like this
[["id":23], ["name":"Jacob"], ["link":{......, ......}]] and so on
I am doing this so that I can append an ID for each.
My best guess I would loop through the array and append an ID/a flag for each element, which I don't know how to do as well.... how to address this issue ? thanks
var arr = [];
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
var innerObj = {};
innerObj[prop] = obj[prop];
arr.push(innerObj)
}
}
console.log(arr);
here is demo https://plnkr.co/edit/9PxisCVrhxlurHJYyeIB?p=preview
p.forEach( function (country) {
country.forEach( function (entry) {
entry.push( {"value" : 'Greece', "synonyms" : 'GR'});
});
});
you can try to use experimental Object.entries:
let obj = {
"id": 23,
"name": "Jacob",
"link": {
"rel": "self",
"link": "www.abc.com"
},
"company":{
"data":{
"id": 1,
"ref": 324
}
}};
console.log(Object.entries(obj).map(item => ({[item[0]]:item[1]})));
for unsupported browsers you can use polyfill: https://github.com/es-shims/Object.entries
You could use an iterative/recursive approach with the object and their nested parts. It works for any depths.
function getKeyValue(object) {
return Object.keys(object).reduce(function (result, key) {
return result.concat(
object[key] && typeof object[key] === 'object' ?
getKeyValue(object[key]) :
[[key, object[key]]]
);
}, []);
}
var data = { id: 23, name: "Jacob", link: { rel: "self", link: "www.abc.com" }, company: { data: { id: 1, ref: 324 } } };
console.log(getKeyValue(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use the Object.keys method to get an array of the keys, then use the Array#map method to return a new array containing individual objects for each property.
This ES6 one-liner should do it:
const splitObject = o => Object.keys(o).map(e => ({ [e]: o[e] }));
Or in ES5:
function splitObject(o) {
return Object.keys(o).map(function(e) {
return Object.defineProperty({}, e, {
value: o[e],
enumerable: true
});
});
}
var res = [];
_.transform( {
"id": 23,
"name": "Jacob",
"link": {
"rel": "self",
"link": "www.abc.com"
},
"company": {
"data": {
"id": 1,
"ref": 324
}
}
}, function(result, value, key) {
res.push(key +':'+value);
}, {});
You can use underscore
Supported in all major browser, including IE11
Object.entries() gives you exactly this.
const obj = {
id: 23,
name: 'Jacob',
link: {
rel: 'self',
link: 'www.abc.com'
},
company: {
data: {
id: 1,
ref: 324
}
}
};
Object.entries(obj);
// output:
[
[
"id",
23
],
[
"name",
"Jacob"
],
[
"link",
{
"rel": "self",
"link": "www.abc.com"
}
],
[
"company",
{
"data": {
"id": 1,
"ref": 324
}
}
]
]
var obj=[{"Name":ABC,"Count":123},{"Name":XYZ,"Count":456}];
var arr = [];
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
var innerObj = {};
innerObj[0] = obj[prop];
arr.push(innerObj[0]);
}
}
/* Here above exmple innerobj index set to 0 then we will get same data into arr if u not menstion then arr will conatins arr[0] our result.
then we need to call first record obj arr[0][0] like this*/
const foo = { "bar": "foobar", "foo": "foobar" }
Object.entries(foo)
should result in:
[["bar", "foobar"], ["foo", "foobar"]]
maybe there's a function to pass to convert all commas to colons
Here's the documentation
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries

Categories