Check if key-value pair exists anywhere in multi-dimensional object - javascript

Let's say I want to identify if a key/value-pair exists in any type/level of object, without knowing the object structure before hand. Is this possible?
Example:
Pair to search for: "kod": "REVH"
Object:
{
"names": [{
"name1": "xxx",
"name2": "yyy",
"pn": null,
"functions": [{
"kod": "LE",
"text": "test"
}, {
"kod": "VD",
"text": "test"
}]
}, {
"name1": null,
"name2": "Comp",
"pn": null,
"pn2": "1239992",
"functions": [{
"kod": "REV",
"text": "temp"
}]
}, {
"name1": "Peter",
"name2": "name",
"pn": "2192992",
"pn2": null,
"functions": [{
"kod": "REVH",
"text": "temp"
}]
}]
}

This is possible by using JSON.stringify() and String.prototype.indexOf(). You can simply expose a function that return whether or not the String search is in the Object
let obj={names:[{name1:"xxx",name2:"yyy",pn:null,functions:[{kod:"LE",text:"test"},{kod:"VD",text:"test"}]},{name1:null,name2:"Comp",pn:null,pn2:"1239992",functions:[{kod:"REV",text:"temp"}]},{name1:"Peter",name2:"name",pn:"2192992",pn2:null,functions:[{kod:"REVH",text:"temp"}]}]};
function pairInObject (obj, search) {return JSON.stringify(obj).indexOf(search) != -1 }
console.log(pairInObject(obj,'"kod":"REVH"'))
console.log(pairInObject(obj,'"foo":"bar"'))

This recursive solution uses Array.some(), and Object.values() to iterate the contents of an object/array, and look for the key/value combination:
const searchKeyValue = (data, key, value) => {
// if falsy or not an object/array return false
if(!data || typeof data !== 'object') return false;
// if the value of the key equals value return true
if(data[key] === value) return true;
// return the results of using searchKeyValue on all values of the object/array
return Object.values(data).some((data) => searchKeyValue(data, key, value));
};
const data = {"names":[{"name1":"xxx","name2":"yyy","pn":null,"functions":[{"kod":"LE","text":"test"},{"kod":"VD","text":"test"}]},{"name1":null,"name2":"Comp","pn":null,"pn2":"1239992","functions":[{"kod":"REV","text":"temp"}]},{"name1":"Peter","name2":"name","pn":"2192992","pn2":null,"functions":[{"kod":"REVH","text":"temp"}]}]};
console.log(searchKeyValue(data, 'kod', 'REVH')); // true
console.log(searchKeyValue(data, 'text', null)); // false
console.log(searchKeyValue(data, 'pn', null)); // true

Related

Restructure nested Object

I have a problem. I have an object with this structure like this example.
{
"Name": "Peter",
"Username": "dummy",
"Age": 18,
"moreData": {
"tags": [1,2,3],
"hasCar": true,
"preferences": {
"colors": ["green", "blue"]
}
}
}
I would like to convert it to an array like the following. I am desperate and can not get any further. I have issues as soon I get some nested objects. Does someone have an idea how I can achieve this? Kind Regards
[
{
"key": "Name",
"val": "Peter"
},
{
"key": "Username",
"val": "dummy"
},
{
"key": "Age",
"val": "18"
},
{
"key": "tags",
"val": [1,2,3]
},
{
"key": "hasCar",
"val": true
},
{
"key": "colors",
"val": ["green", "blue"]
}
]
For this you need to first iterate through all the key value pairs of your object and change the specific type of data into name value pairs except the nested objects. If the value in the object at a certain key is an object then the same procedure has to be done for it. And since there can be N number of levels for this nested data thus we need a recursive function for it. Whenever we have to do a same set of processing for nested data then it always means it can be done using recursion. It can be done via for loops too but a recursive function is much clear and lesser to write.
function getData(data) {
let results = [];
Object.keys(data).forEach(key => {
// If the type of the data item is object and is not an array, go into recursion
if(typeof data[key] == 'object' && !Array.isArray(data[key])) {
results = results.concat(getData(data[key]));
} else {
results.push({ key, val: data[key] });
}
});
return results;
}
const data = {
"Name": "Peter",
"Username": "dummy",
"Age": 18,
"moreData": {
"tags": [1,2,3],
"hasCar": true,
"preferences": {
"colors": ["green", "blue"]
}
}
};
const results = getData(data);
console.log(results);
// [{"key":"Name","val":"Peter"},{"key":"Username","val":"dummy"},{"key":"Age","val":18},{"key":"tags","val":[1,2,3]},{"key":"hasCar","val":true},{"key":"colors","val":["green","blue"]}]

How to search through multi layers nested objects by keys in js

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

Check if nested arrays in object contains empty values

Consider the following object:
{
"params": {
"time_to_diagnosis": [
{
"field": "date_of_diagnosis",
"value": ""
},
{
"field": "date_of_symptom_onset",
"value": "2019-09-01"
}
],
"time_since_onset": [
{
"field": "date_of_symptom_onset",
"value": "2019-09-01"
}
]
}
}
As you can tell this is a object , of objects with arrays that them selves contains objects.
As you can see some keys are empty.
The idea is that if there are no empty keys in the arrays containing objects, then return true, else return false.
Heres what I wrote:
const isParamsInAjaxParamsEmpty = (paramsForAjaxCall) => {
for (const key in paramsForAjaxCall) {
for (const nestedKey in paramsForAjaxCall[key]) {
const params = paramsForAjaxCall[key];
if (params[nestedKey] === "") {
return true;
}
}
}
return false;
}
I Know I can do an Array.isArray on the nestedKey part, but Im not sure how to make this recursive, as there could be one or more arrays.
paramsForAjaxCall is the object above.
Thoughts?
you can map the array then take the values from the Object and with every will get a boolean value so it's an array of booleans in the end because we mapping.
if this array contains a false so the result is false
const data = {
"params": {
"time_to_diagnosis": [{
"field": "date_of_diagnosis",
"value": "ddd"
},
{
"field": "date_of_symptom_onset",
"value": "2019-09-01"
}
],
"time_since_onset": [{
"field": "date_of_symptom_onset",
"value": "2019-09-01"
}]
}
}
const res = !Object.values(data).map(o => Object.values(o).map(value => value.every(({
value
}) => value !== ""))).flat().includes(false)
console.log(res)
You could take a check for not object and return false, then check for the wanted property or iterate all properties.
function check(object) {
if (!object || typeof object !== 'object') return false;
if (object.value) return true;
return Object.values(object).every(check);
}
var object = { params: { time_to_diagnosis: [{ field: "date_of_diagnosis", value: "" }, { field: "date_of_symptom_onset", value: "2019-09-01" }], time_since_onset: [{ field: "date_of_symptom_onset", value: "2019-09-01" }] } }
console.log(check(object));
object.params.time_to_diagnosis[0].value= "foo";
console.log(check(object));

Convert array of objects into lowercase

Array looks like this:
"myTags":
[{
"type":"one",
"value":"Testing",
"note":"Hey"
},{
"type":"two",
"value":"Yg5GE",
"note":"hey2"
}]
I need to convert type:'one' value 'Testing' into lowercase i.e. value = Testing needs to be 'testing'. Is there a way to so this keeping the same structure?
Note: "type":"one","value":"Testing", may not always be included in the array. So I guess in this scenario I first need to do a check if they exist?
I have tried .map, however I am unable to get the result I want. Any help would be appreciated.
Ideal structure:
"myTags":
[{
"type":"one",
"value":"testing",
"note":"hey"
},{
"type":"two",
"value":"Yg5GE",
"note":"hey2"
}]
Iterate over the elements in myTags, check if type is "one" and only then change the content of value to lowercase (if present)
var data = {
"myTags": [{
"type": "one",
"value": "Testing",
"note": "Hey"
}, {
"type": "one",
"note": "Hey"
}, {
"type": "two",
"value": "Yg5GE",
"note": "hey2"
}]
};
data.myTags.forEach(function(tag) {
if (tag.type === "one" && typeof tag.value !== "undefined") {
tag.value = tag.value.toLowerCase();
}
});
console.log(data.myTags);
You may also first filter the content of myTags to get the element(s) with "type": "one" and only iterate over those element(s)
var data = {
"myTags": [{
"type": "one",
"value": "Testing",
"note": "Hey"
}, {
"type": "one",
"note": "Hey"
}, {
"type": "two",
"value": "Yg5GE",
"note": "hey2"
}]
};
data.myTags
.filter(function(tag) {
return tag.type === "one";
})
.forEach(function(tag) {
if (typeof tag.value !== "undefined") {
tag.value = tag.value.toLowerCase();
}
});
console.log(data.myTags);
This one works perfectly
$(document).ready(function(){
var objects ={"myTags":
[{"type":"one","value":"Testing", "note":"Hey"}
,{ "type":"two", "value":"Yg5GE", "note":"hey2"}]};
var obj = objects.myTags.map(function(a) {
a.value = a.value.toLowerCase();
return a;
});
console.log(obj);
});
output:
{type: "one", value: "testing", note: "Hey"}
{type: "two", value: "yg5ge", note: "hey2"}
Thank you
Achieve this very simply by using an arrow function and the map() method of the Array
var words = ['Foo','Bar','Fizz','Buzz'].map(v => v.toLowerCase());
console.log(words);

Iterate through the child objects and get all the values with javascript

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);
}

Categories

Resources