i have a object which has identifiers:
const cities = {
"0": {
"city": "Bielsko-Biała",
"country": "PL",
},
"1": {
"city": "Kielce",
"country": "PL",
},
"2": {
"city": "Kłodzko",
"country": "PL",
}
}
What i want is to remove 0, 1, 2 and so on to get this format:
const cities = [
{
"city": "Bielsko-Biała",
"country": "PL",
},
{
"city": "Kielce",
"country": "PL",
},
{
"city": "Kłodzko",
"country": "PL",
}
]
It is neccessary to me because i want to add description to every city and i couldn't map in this object because of that format.
I had to do something like that in React and i think it is a very bad written code:
const cities = [];
countries.map(el => {
cities.push(el.city)
})
let updatedCountries = countries;
cities.forEach((city) => {
axios.get(`https://en.wikipedia.org/api/rest_v1/page/summary/${city}`)
.then(response => {
for (let property in updatedCountries) {
if (updatedCountries.hasOwnProperty(property)) {
if (updatedCountries[property].city === city) {
updatedCountries[property]['description'] = response.data.description
}
}
}
})
})
this.setState({
countries: updatedCountries
})
You can use Object.values()
The Object.values() method returns an array of a given object's own enumerable property values,
const cities = {
"0": {
"city": "Bielsko-Biała",
"country": "PL",
},
"1": {
"city": "Kielce",
"country": "PL",
},
"2": {
"city": "Kłodzko",
"country": "PL",
}
}
let values = Object.values(cities);
console.log(values);
Related
I need to flatten the json, but want to consider an exclusion_keys_array list which are not to be processed/added to the list
for example
if I have an exclusion_keys_array = ["addresses.metadata", "pageToken"]
//only metadata of addresses will be skipped (second level skip)
if I have an exclusion_keys_array = ["metadata", "pageToken"]
//metadata of parent json will be skipped (top level key skip)
How do I flatten a JSON using an exclusion array?
Code source: Dynamically generate a 2d array from JSON with varying columns
var exlusion_list = ["metadata", "meta", "pageToken"];
var crowds = [{
"name": [{
"firstName": "John",
"middleName": "Joseph",
"lastName": "Briggs",
}],
"addresses": [{
"type": "home",
"poBox": "111",
"city": "City1",
"postalCode": "1ER001",
"country": "USA",
}, {
"type": "work",
"poBox": "222",
"city": "City2",
"region": "Region2",
"postalCode": "1ER002",
}],
"photos": [{
"url": "photo.org/person1",
"default": true,
}, {
"url": "imagur.org/person1",
"default": true,
}],
"metadata": [{
"meta-id": "1234",
}],
}, {
"name": [{
"firstName": "Bill",
"lastName": "Thatcher",
}],
"addresses": [{
"type": "home",
"city": "City3",
"region": "Region3",
"postalCode": "1ER003",
"country": "USA",
}, {
"type": "work",
"poBox": "444",
"region": "Region4",
"postalCode": "1ER004",
}, {
"poBox": "555",
"region": "Region5",
"postalCode": "1ER005",
}],
"metadata": [{
"meta-id": "1234",
}],
}];
function flatten(obj, res = {}, key = '') {
let add = (d, s) => key ? key + d + s : s;
if (Array.isArray(obj)) {
obj.forEach((v, n) => flatten(v, res, add(' #', n + 1)));
} else if (typeof obj === 'object') {
Object.entries(obj).forEach(([k, v]) => flatten(v, res, add(': ', k)));
} else {
res[key] = obj;
}
return res;
}
let flats = crowds.map(obj => flatten(obj));
function combineKeys(objs) {
let keys = objs.reduce((k, obj) => k.concat(Object.keys(obj)), []);
return [...new Set(keys)];
}
let keys = combineKeys(flats);
let table = flats.map(f => keys.map(k => f[k] ?? ''));
table.unshift(keys);
console.log({ table });
// document.write(JSON.stringify(table));
.as-console-wrapper { min-height: 100%!important; top: 0; }
// .as-console-wrapper { min-height: 70%!important; bottom: 0; }
A quick fix would be filter the keys like below. I think there is a more efficient way to do it but I didn't look into the codes too deep.
let keys = combineKeys(flats).filter(
key => !exlusion_list.includes(key.split(":")[0].split(" ")[0])
);
I want to simplify nested array of object to array of string without altering original array, but value of countries array of object get changed. How I will rectify so I'll get new array of object in newCountries and old value of array of object not get modified. i/e countries
const countries = {
"country": [{
"name": "India",
"cities": [{
"name": "Mumbai",
},
{
"name": "Delhi",
}
]
},
{
"name": "Australia",
"cities": [{
"name": "Sydney",
},
{
"name": "Melbourne",
}
]
}
]
}
// I have tried following code
var newCountries = Object.assign({}, countries);
newCountries.country.map(val => {
if (val.cities) {
var city = val.cities.map(city => {
return city.name
});
val.cities = [];
val.cities = city;
}
return val;
})
console.log('new object\n', newCountries)
console.log('old object\n', countries)
<b>output</b>
<pre>
{
"country": [
{
"name": "India",
"cities": [
"Mumbai",
"Delhi"
]
},
{
"name": "Australia",
"cities": [
"Sydney",
"Melbourne"
]
}
]
}
</pre>
Well, this is a trivial task. Just loop over each country and assign a new array of city names to the existing one by mapping the object to just the value of the "name" key.
You could also try this, assuming name is the only key in the object.
country.cities = country.cities.reduce((arr, city) => arr.concat(Object.values(city)), [])
You can even simplify this further by using Array.prototype.flatMap:
country.cities = country.cities.flatMap(city => Object.values(city))
Note: flatMap is somewhat of an experimental feature in modern browsers.
Chrome – Version 69 (2018-09-04)
Edge – No
Firefox – Version 62 (2019-09-03)
Internet Explorer – No
Opera – Version 56 (2018-09-25 → Chromium 69)
Safari – Version 12 (2018-09-17)
const countries = {
"country": [{
"name": "India",
"cities": [{
"name": "Mumbai",
}, {
"name": "Delhi",
}]
}, {
"name": "Australia",
"cities": [{
"name": "Sydney",
}, {
"name": "Melbourne",
}]
}]
}
// Loop over each country
countries.country.forEach(country => {
// Replace `{ name : "CITY_NAME" }` with just `"CITY_NAME"`
country.cities = country.cities.map(city => city.name)
})
console.log(countries);
.as-console-wrapper { top: 0; max-height: 100% !important; }
I have a sample object structure like below
Even though there are three types of addresses (address, employeeAddress, shippingAddress), they all represent the same data structure called address. From this object structure, I need to get all the addresses from the above structure.The object structure might be defined in using a JSON Schema format.
Also the addresses need not be always as part of the same hierarchy. For example in the above, shippingAddress and employeeAddress are at different hierarchy.
I tried with object's hasOwnProperty, but did not work the way as expected. Did not get much help from the filter method in lodash also. Is there an elegant way to achieve this?
{
"user": {
"firstName": "John",
"lastName": "Steve",
"address": {
"houseNo": "24",
"city": "CA",
"country": {
"code": "US",
"name": "United States"
}
}
},
"employee": {
"employeeID": "443434",
"employeeName": "Steve",
"employeeAddress": {
"houseNo": "244",
"city": "NJ",
"country": {
"code": "US",
"name": "United States"
}
}
},
"assistant": {
"assitantID": "443434",
"employeeName": "Steve",
"shippingDetails": {
"shippingAddress": {
"houseNo": "2444",
"city": "LA",
"country": {
"code": "US",
"name": "United States"
}
}
}
}
}
You could use recursion for this and create a function that takes input data and schema object. Then on each level another function checks if the current object matches schema structure.
const data = {"user":{"firstName":"John","lastName":"Steve","address":{"houseNo":"24","city":"CA","country":{"code":"US","name":"United States"}}},"employee":{"employeeID":"443434","employeeName":"Steve","employeeAddress":{"houseNo":"244","city":"NJ","country":{"code":"US","name":"United States"}}},"assistant":{"assitantID":"443434","employeeName":"Steve","shippingDetails":{"shippingAddress":{"houseNo":"2444","city":"LA","country":{"code":"US","name":"United States"}}}}}
const schema = {
houseNo: null,
country: null,
city: null
}
function match(o1, o2) {
return Object.keys(o1).every(k => k in o2);
}
function get(data, schema) {
return Object.keys(data).reduce((r, e) => {
if (match(data[e], schema)) r.push(data[e]);
else if (typeof data[e] == 'object') r.push(...get(data[e], schema));
return r;
}, [])
}
const result = get(data, schema);
console.log(result)
Here is a plain JS version of one found here
var user = { "user": { "firstName": "John", "lastName": "Steve", "address": { "houseNo": "24", "city": "CA", "country": { "code": "US", "name": "United States" } } }, "employee": { "employeeID": "443434", "employeeName": "Steve", "employeeAddress": { "houseNo": "244", "city": "NJ", "country": { "code": "US", "name": "United States" } } }, "assistant": { "assitantID": "443434", "employeeName": "Steve", "shippingDetails": { "shippingAddress": { "houseNo": "2444", "city": "LA", "country": { "code": "US", "name": "United States" } } } } }
function findProp(obj, prop) {
var result = {};
function recursivelyFindProp(o, keyToBeFound) {
Object.keys(o).forEach(function (key) {
if (typeof o[key] === 'object') {
if (key.toLowerCase().indexOf(keyToBeFound) !==-1) result[key]=o[key];
recursivelyFindProp(o[key], keyToBeFound);
} else {
if (key.toLowerCase().indexOf(keyToBeFound) !==-1) result[key]=o[key];
}
});
}
recursivelyFindProp(obj, prop);
return result;
}
console.log(
findProp(user, "address")
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
Hi I need to construct to url request with query parameter, I have a nested object with the key and values, like below
"user": {
"first_name": "Srini",
"last_name": "Raman",
"gender": "male",
"dob": "1992-08-02",
"address_attributes": {
"city": "San Diego",
"state": "CA",
"zip": 92127,
"country": "USA",
"latitude": 37.257009,
"longitude": -120.050767
}
}
i need to get a query parameter like
user[first_name]=Srini&user[last_name]=Raman&user[address_attributes][city]=San Diego&user[address_attributes][state]=CA
let obj = {
user: {
first_name: 'Srini',
last_name: 'Raman',
gender: 'male',
dob: '1992-08-02',
address_attributes: {
city: 'San Diego',
state: 'CA',
zip: 92127,
country: 'USA',
latitude: 37.257009,
longitude: -120.050767
}
}
};
let getPairs = (obj, keys = []) =>
Object.entries(obj).reduce((pairs, [key, value]) => {
if (typeof value === 'object')
pairs.push(...getPairs(value, [...keys, key]));
else
pairs.push([[...keys, key], value]);
return pairs;
}, []);
let x = getPairs(obj)
.map(([[key0, ...keysRest], value]) =>
`${key0}${keysRest.map(a => `[${a}]`).join('')}=${value}`)
.join('&');
console.log(x);
You can use the qs package.
Their stringify method seems to do exactly what you want.
Usage example:
window.addEventListener("load", () => {
const obj = {
"user": {
"first_name": "Srini",
"last_name": "Raman",
"gender": "male",
"dob": "1992-08-02",
"address_attributes": {
"city": "San Diego",
"state": "CA",
"zip": 92127,
"country": "USA",
"latitude": 37.257009,
"longitude": -120.050767
}
}
};
console.log(Qs.stringify(obj, { encode: false }));
}, {
once: true
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/qs/6.11.0/qs.min.js"></script>
Here is a TypeScript implementation if someone needs it.
const testObject = {
"user": {
"first_name": "Srini",
"last_name": "Raman",
"gender": "male",
"dob": "1992-08-02",
"address_attributes": {
"city": "San Diego",
"state": "CA",
"zip": 92127,
"country": "USA",
"latitude": 37.257009,
"longitude": -120.050767
}
}
}
interface ObjectToQueryStringHelperObject {
keyPath: Array<string>;
value: boolean | number | string;
}
function objectToQueryStringHelper(
object: any,
path: Array<string> = [],
result: Array<ObjectToQueryStringHelperObject> = []
): Array<ObjectToQueryStringHelperObject> {
return Object.entries(object).reduce((acc, [key, value]) => {
if (!_.isNil(value) || !_.isEmpty(value)) {
_.isObject(value) ?
acc.push(...objectToQueryStringHelper(value, [...path, key], result)) :
acc.push({ keyPath: [...path, key], value });
}
return acc;
}, []);
}
export function objectToQueryString(object: any): string {
const simplifiedData = objectToQueryStringHelper(object);
const queryStrings = simplifiedData.map(({ keyPath: [firstKey, ...otherKeys], value }) => {
const nestedPath = otherKeys.map(key => `[${key}]`).join('');
return `${firstKey}${nestedPath}=${!_.isNil(value) ? encodeURI(`${value}`) : ''}`
})
return queryStrings.join('&');
}
console.log(objectToQueryString(testObject))
var json = [{
"city": "California",
"name": "Joe",
"age": 17,
"type",:"custom"
}, {
"city": "California",
"name": "Bob",
"age": 17,
"type",:"predefined"
}, {
"city": "California",
"name": "Bob",
"age": 35,
"type",:"custom"
}, {
"city": "Texas",
"name": "Bob",
"age": 35,
"type",:"custom"
}, {
"city": "Florida",
"name": "Bob",
"age": 35,
"type",:"predefined"
}];
I have above array and i have to construct object, based on "type" value i.e "predefined" or "custom" as below
updatedjson = {
"predefined": [{
"name": "California",
"count": 1
}, {
"name": "Florida",
"count": 1
}]
"custom": [{
"name": "California",
"count": 2
}, {
"name": "Texas",
"count": 1
}]
}
Any Approach using javascript or lodash
Using Lodash
var json = [{
"city": "California",
"name": "Joe",
"age": 17,
"type": "custom"
}, {
"city": "California",
"name": "Bob",
"age": 17,
"type": "predefined"
}, {
"city": "California",
"name": "Bob",
"age": 35,
"type": "custom"
}, {
"city": "Texas",
"name": "Bob",
"age": 35,
"type": "custom"
}, {
"city": "Florida",
"name": "Bob",
"age": 35,
"type": "predefined"
}];
// Solution to the problem
var updatedJson = _(json).groupBy("type").value(); // #1
_.forOwn(updatedJson, function(value, key) {
let countByCity = _(value).countBy('city').value(); // #2
let res = [];
_.forOwn(countByCity, function(value, key) {
res.push({ // #3
name: key,
count: value
});
});
updatedJson[key] = res;
});
console.log(updatedJson);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script>
Explanation
Code first groups by type
Then counts by cities, within the group
Finally pushes the count object into an array, in the expected format
You can use reduce & findIndex
var json = [{
"city": "California",
"name": "Joe",
"age": 17,
"type": "custom"
}, {
"city": "California",
"name": "Bob",
"age": 17,
"type": "predefined"
}, {
"city": "California",
"name": "Bob",
"age": 35,
"type": "custom"
}, {
"city": "Texas",
"name": "Bob",
"age": 35,
"type": "custom"
}, {
"city": "Florida",
"name": "Bob",
"age": 35,
"type": "predefined"
}];
var updatedjson = json.reduce(function(result, item) {
// check if type is present in the object
// if not present then add a key by name custom/predefined
if (!result[item.type]) {
result[item.type] = [];
// add city name and intial count
result[item.type].push({
name: item.city,
count: 1
})
} else {
// now find the index of the object whe name matches with current city
let m = result[item.type].findIndex(function(obj) {
return obj.name === item.city
})
// if no matches then add the new object to either custom/predefined
if (m === -1) {
result[item.type].push({
name: item.city,
count: 1
})
} else {
// if matches then increase the value of count
result[item.type][m].count += 1
}
}
return result;
}, {});
console.log(updatedjson)
You can use array.reduce to create a new object with the aggregated data. Example:
const result = json.reduce((obj, data) => {
// if this is a new type, we must initialize it as an empty array and push the first record.
if(!obj[data.type]) {
obj[data.type] = [];
obj[data.type].push({name: data.city, count: 1});
return obj;
}
// else ... check if the current city is present in that type
const existingRecord = obj[data.type].find(d => d.name === data.city);
if(!existingRecord) {
// if the city is not present in that type, we initialize it with count 1
obj[data.type].push({name: data.city, count: 1});
return obj;
}
// if the city is present, we just update count = count + 1;
existingRecord.count++;
return obj;
}, { })
Now, you probably want to extract some of that logic into separate functions to increase readability. I don't think you need lodash for this but in the case you already have it included in your project then feel free to use it :P