Below is the json data that I have which contains array of states. The size of array is always 2, but the order of elements of the array is not fixed. The array elements values can be null. The sample data is as shown below:
{
"status": "SUCCESS",
"status_message": "Susscessfully queried details.",
"total_records": 2,
"m_details":
[
{
"p_id": 1023,
"pname": "india",
"states":
[
{
"state": "karnataka",
"capital": "bangalore"
},
{
"state": null,
"capital": null,
}
]
},
{
"p_id": 1023,
"pname": "india",
"states":
[
{
"state": null,
"capital": null
},
{
"state": "Tamilnadu",
"capital": "chennai"
}
]
}
]
}
My questions:
How to convert the null values to some default text say "-".
How can I sort all the states in asc or desc order.
You can iterate through all elements in your data to switch any null values to "-" with an iterator with a callback like this.
function iterateObject(item, callback) {
if (typeof item === "object" && item !== null) {
if (item instanceof Array) {
for (var i = 0; i < item.length; i++) {
item[i] = iterateObject(item[i], callback);
}
} else {
for (var prop in item) {
if (item.hasOwnProperty(prop)) {
item[prop] = iterateObject(item[prop], callback);
}
}
}
} else {
// call the callback on any item that is not an array or object
return callback(item);
}
return item;
}
var data = {
"status": "SUCCESS",
"status_message": "Susscessfully queried details.",
"total_records": 2,
"m_details":
[
{
"p_id": 1023,
"pname": "india",
"states":
[
{
"state": "karnataka",
"capital": "bangalore"
},
{
"state": null,
"capital": null,
}
]
},
{
"p_id": 1023,
"pname": "india",
"states":
[
{
"state": null,
"capital": null
},
{
"state": "Tamilnadu",
"capital": "chennai"
}
]
}
]
};
// iterate through the object and convert all `null` values to `"-"`
iterateObject(data, function(item) {
return (item === null) ? "-" : item;
});
You can then sort each of the states arrays like this:
function sortStates(item) {
var array = item.m_details;
for (var i = 0; i < array.length; i++) {
array[i].states.sort(function(a, b) {
return a.state.localeCompare(b.state);
});
}
}
sortStates(data);
If you want the opposite sort order, then just swap the arguments a and b in the .sort() callback.
Working demo: http://jsfiddle.net/jfriend00/MTQ86/
Just for your information javascript array objects have a sort function that implements some basic built in sorting functionalities. If you need to perform a more specific sorting (you do) you can always passing in a function to the sort function and implement your own custom logic. This article from W3Schools has some examples which quoting one of them here...
var points = [40,100,1,5,25,10];
points.sort(function(a,b){return b-a}); //sorts numbers in descending order
Now, to "convert" null values to a '-' literal I guess you will need to add more details to your question so I can provide a good solution. Why do you need to convert them? Where's this json coming from?
Related
I would like to search through multi layered nested object in javascript. The number of layers is dynamic.Not fixed.
Let's say I have an object like this.
data={
"_index": "sample_data_logs",
"_type": "_doc",
"_id": "lDMTgnEBbYNxp5GHN-gj",
"_version": 1,
"_score": 7.6343846,
"_source": {
"agent": "Mozilla/4.0",
"bytes": 6948,
"clientip": "172.3.128.226",
"extension": "",
"geo": {
"srcdest": "IN:BY",
"src": "IN",
"dest": "BY",
"coordinates": {
"lat": 41.92076333,
"lon": -71.49138139
}
},
"host": "www.host.co",
"index": "sample_data_logs",
"ip": "172.3.128.226",
"machine": {
"ram": 5368709120,
"os": "win 8"
},
"memory": null,
"phpmemory": null,
"request": "/apm",
"response": 200,
"tags": [
"success",
"security"
],
"timestamp": "2020-04-13T11:05:05.551Z",
"url": "https://www.elastic.co/downloads/apm",
"utc_time": "2020-04-13T11:05:05.551Z"
}
}
keys= ["_index","bytes","os","tags"];
And I have an array of key values to find or filter in data.
How can I do that?
Using lodash I have tried
_.pick(data_, keys);
I don't get the expected results which should be:
{
"_index": "sample_data_logs",
"bytes": 6948,
"os": "win 8",
"tags": [
"success",
"security"
]
}
What is the best way of doing this? can it be done in vanilla js?
You need to traverse your data recursively, like this:
Explanation:
We have a function traverse that takes:
an object (called data),
a list of keys (called keys),
and an object that contains the current result (the found key/value pairs called result)
In the traverse function, we go over the first level keys of object data (using Object.keys(data)) and we check if each of them is in the keys list, and if it is then we add that key/value pair to the result and go to the next one.
But if it is not in the keys, then we need to check if that key is a nested object, so we do that with this conditions:
if (
data[k] &&
typeof data[k] === "object" &&
Object.keys(data[k]).length > 0
)
The first one (data[k]) is used to rule out null and undefined
The second one (typeof data[k] === "object") is used to check if the value is an object
The third condition is used to rule out native objects like Date
And if it is a nested object, then we call the traverse (recursive) again
let data = {
_index: "sample_data_logs",
_type: "_doc",
_id: "lDMTgnEBbYNxp5GHN-gj",
_version: 1,
_score: 7.6343846,
_source: {
agent: "Mozilla/4.0",
bytes: 6948,
clientip: "172.3.128.226",
extension: "",
geo: {
srcdest: "IN:BY",
src: "IN",
dest: "BY",
coordinates: {
lat: 41.92076333,
lon: -71.49138139,
},
},
host: "www.host.co",
index: "sample_data_logs",
ip: "172.3.128.226",
machine: {
ram: 5368709120,
os: "win 8",
},
memory: null,
phpmemory: null,
request: "/apm",
response: 200,
tags: ["success", "security"],
timestamp: "2020-04-13T11:05:05.551Z",
url: "https://www.elastic.co/downloads/apm",
utc_time: "2020-04-13T11:05:05.551Z",
},
};
let keys = ["_index", "bytes", "os", "tags"];
function traverse(data, keys, result = {}) {
for (let k of Object.keys(data)) {
if (keys.includes(k)) {
result = Object.assign({}, result, {
[k]: data[k]
});
continue;
}
if (
data[k] &&
typeof data[k] === "object" &&
Object.keys(data[k]).length > 0
)
result = traverse(data[k], keys, result);
}
return result;
}
result = traverse(data, keys);
console.log(result);
You can use :
const object1 = {
a: 'somestring',
b: 42
};
for (let [key, value] of Object.entries(object1)) {
if (key === target) {// do somethings}
}
If the keys is equal to your need, you can perform your treatment ?
Hope it's help
I have one javascript array and one object . Need help to sort javascript object keys based on the order number in another array
In subgroup array , I have name , order number. Need to sort Offerings keys based on that order number
const subgroup = [
{
"code": "6748",
"name": "test123",
"orderNumber": "0"
},
{
"code": "1234",
"name": "customdata",
"orderNumber": "1"
}
]
const offerings = {
"customdata" : [
{
"code": "Audi",
"color": "black"
}
],
"test123" : [
{
"brand": "Audi",
"color": "black"
}
]
}
I believe this should work for you. I've added some comments in the code that should hopefully do an okay job of explaining what is happening.
var subgroup = [{
"code": "6748",
"name": "test123",
"orderNumber": "0"
}, {
"code": "1234",
"name": "customdata",
"orderNumber": "1"
}];
var offerings = {
"customdata": [{
"code": "Audi",
"color": "black"
}],
"test123": [{
"brand": "Audi",
"color": "black"
}]
}
function sortObjectFromArray(refArray, sortObject, orderKey = 'order', linkKey = 'key') {
// Get copy of refArray
let reference = refArray.slice();
// Sort sortObject [ into an array at this point ]
let sorted = [];
for (let key in sortObject) {
// Searches the refArray for the linkKey, and returns the intended index
let index = reference.find((item) => item[linkKey] === key)[orderKey];
// Places the sortObject's value in the correct index of the 'sorted' Array
sorted[parseInt(index)] = [key, sortObject[key]];
};
// Return an object, created from previous 'sorted' Array
return sorted.reduce((obj, [key, value]) => {
obj[key] = value;
return obj;
}, {});
};
offerings = sortObjectFromArray(subgroup, offerings, 'orderNumber', 'name');
console.log(offerings);
I have this object with nested arrays/objects:
{
"USA": [
{
"location": "New York",
"municipality": "Manhattan",
},
{
"location": "Texas",
"municipality": "Austin",
}
],
"CANADA": [
{
"location": "Ontario",
"municipality": "no municipality",
}
]
}
I want to use lodash or plain javascript to count how many location are inside the USA and CANADA. How is that possible?
desired result:
USA: 2
CANADA: 1
Just use the array lengths:
var USA = myObj.USA.length;
var Canada = myObj.CANADA.length;
Or, for larger data sets:
var result = {};
Object.keys(myObj)
.forEach(function(key,index) {
result[key] = myObj[key].length;
});
With lodash you could use mapValues:
let result = _.mapValues(data, 'length');
The solution using Array.prototype.reduce() function:
var obj = {
"USA": [ { "location": "New York", "municipality": "Manhattan" }, { "location": "Texas", "municipality": "Austin" } ], "CANADA": [ { "location": "Ontario", "municipality": "no municipality" }]
},
result = Object.keys(obj).reduce(function(r,k){
r[k] = obj[k].length;
return r;
}, {});
console.log(result)
var formmd = {
"frmType": "Registration",
"frmStage": "step1-complete",
"formattr": {
"SystemUser": {
"LoginName": "A#test.com",
"Password": "password",
"PIN": "",
"IsTestUser": false
},
"ConsumerAddress": {
"AddressLine1": "201 MOUNT Road",
"AddressLine2": null,
"AddressTypeId": "1",
"City": "OLA TRAP",
"State": "NM",
"Zipcode": "60005"
},
"ConsumerPhone": {
"PhoneTypeId": 6,
"PhoneNumber": "9876543210",
"PrimaryPhoneIndicator": null,
"AllowVoicemail": false
},
"PhysicianSpecialty": {
"SpecialtyList": [
"1",
"2"
]
},
}
}
I'm trying to fetch all the values of the child objects under formattr but I'm unable to iterate inside the child objects. The following is the script I tried.
My Result should be
"A#test.com"
"password"
"PIN": ""
False
201 MOUNT Road"
The script I tried is
function walk(formmd) {
var obj1 = formmd.formattr;
for(var key in obj1){
if (obj1.hasOwnProperty(key)) {
var val1 = obj1[key];
if(val1.hasOwnProperty(key)){
for(var key in val1){
var val2 =val1[key];
console.log("val2");
}
}
}
}
}
How to access the keys of child objects in an automated way?
Try like this
for (var key in formmd) {
var val1 = formmd[key];
if (key=="formattr") {
for (var key1 in val1) {
var val2 = val1[key1];
for(var key2 in val2)
console.log(val2[key2]);
}
}
}
DEMO
You might find it easier to understand code written in a functional style. This is one solution, which I'll explain:
Object.values(formmd.formattr)
.map(obj => Object.values(obj))
.reduce((acc, vals) => acc.concat(vals), [])
The first expression Object.values(formmd.formattr) gives you an array of all the values (not keys) under formmd.formattr. Something like:
[{"LoginName": "A#test.com", "Password": "password", …}, {"AddressLine1": "201 MOUNT Road", "AddressLine2": null, …}, …]
Since you want the values within each of these sub-objects the next line .map(obj => Object.values(obj)) will do just that. It returns a new array where each object in the input array is transformed through Object.values(…). It returns something like:
[["A#test.com", "password", "", false], ["201 MOUNT Road", null, "1", …], …]
This array has all the data you're after, but in nested arrays, so it needs to be flattened with .reduce((acc, vals) => acc.concat(vals), []). This reduce will successively concat these sub-arrays to produce a single array like:
["A#test.com", "password", "", false, "201 MOUNT Road", null, "1", …]
which contains all the values of the child objects under formattr.
Here's some other ways to do it:
Object.values(formmd.formattr)
.reduce((acc, x) => acc.concat(Object.values(x)), [])
or
[].concat(...
Object.values(formmd.formattr)
.map(obj => Object.values(obj)))
You will have to use Object.entries()
The Object.entries() method returns an array of a given object's own
enumerable string-keyed property [key, value] pairs, in the same order
as that provided by a for...in loop. (The only important difference is
that a for...in loop enumerates properties in the prototype chain as
well).
Example -
for (const [key, value] of Object.entries(objectName)) {
console.log(`${key}: ${value}`);
}
Code Snippet -
var formmd = {
"frmType": "Registration",
"frmStage": "step1-complete",
"formattr": {
"SystemUser": {
"LoginName": "A#test.com",
"Password": "password",
"PIN": "",
"IsTestUser": false
},
"ConsumerAddress": {
"AddressLine1": "201 MOUNT Road",
"AddressLine2": null,
"AddressTypeId": "1",
"City": "OLA TRAP",
"State": "NM",
"Zipcode": "60005"
},
"ConsumerPhone": {
"PhoneTypeId": 6,
"PhoneNumber": "9876543210",
"PrimaryPhoneIndicator": null,
"AllowVoicemail": false
},
"PhysicianSpecialty": {
"SpecialtyList": [
"1",
"2"
]
},
}
}
for (const [key, value] of Object.entries(formmd.formattr)) {
console.log('Value',value);
}
{
"_id": {
"$oid": "5705f793e4b0acd6e2456804a"
},
"Categories": [
{
"mainmodels": [
{
"submodels": [
{
"price": "2000",
"submodelname": "lumia021",
"Remainingphones": "2",
"Bookedphones": "8",
"Numofphones": "10"
},
{
"price": "4000",
"submodelname": "lumia K6",
"Remainingphones": "0",
"Bookedphones": "15",
"Numofphones": "15"
}
],
"Status": "Active",
"modelname": "lumia",
"fromdate": "2016-04-01T16:39:12.051Z",
"todate": "2016-04-31T19:19:44.051Z"
}
],
"brand": "nokia"
}
],
"rank": "1",
"name": "kalasipalaya"
}
I have given my object above i need to check every submodel(here two sumodels is there)Numofphones and Bookedphones are matched . if both(here i given two submodel) Numofphones and Bookedphones are matched i need to print matched otherwise i need to print not matched how can i solve this one help me out .
//This will take to submodel array of object
var _getSubModel = m[0].Categories[0].mainmodels[0].submodels;
var _newArray2 = [];
//Checking if Bookedphones of first object submodel, is same with other objects.
var _newArray = _getSubModel.filter(function(item){
return item.Bookedphones == _getSubModel[0].Bookedphones;
})
// If all the Bookedphones are same then length of _newArray & submodel will be same.
// If same then check for Numofphones
if(_getSubModel.length == _newArray.length){
_newArray2 = _getSubModel.filter(function(item){
return item.Numofphones == _getSubModel[0].Numofphones;
})
// If all Numofphones are same,then length of _newArray2 & submodel will be same
if(_getSubModel.length == _newArray2.length){
console.log('Matched');
}
else{
console.log('Not Matched');
}
}
else{
console.log('Not Matched');
}
Check this jsfiddle
You can use custom filter something like that:
var result = [];
angular.forEach(submodels, function (submodel) {
if(submodel.Numofphones == submodel.Bookedphones)
result.push(submodel);
});
return result;
http://jsfiddle.net/y7r1xe0t/236/
UPDATED: http://jsfiddle.net/y7r1xe0t/237/
return function (submodels, matched_or_not) {
var result = [];
angular.forEach(submodels, function (submodel) {
if(matched_or_not && submodel.Numofphones == submodel.Bookedphones)
result.push(submodel);
else if(!matched_or_not && submodel.Numofphones != submodel.Bookedphones)
result.push(submodel);
});
return result;
};
Filter will return matched object when you send true.