I have an object that looks like this:
{house_id+street_id+school_id: {...}, house_id2+street_id2+school_id2: {...}, ...}
So, each key of the object is a combination of a house_id a street_id and a school_id separated by '+' sign.
I want to be able to filter the object given a street_id, so for example, for the given object:
{40+30+20: { name: "john" }, 41+31+20: { name: "eli" } } and the street_id being 30, the returning object would be:
{40+30+20: "john"}
How can I do that filtering?
You can do it in the following way
let obj = {'40+30+20': { name: "john" }, '41+31+20': { name: "eli" } }
let result = Object.keys(obj).filter(e => e.match(/^.*\+30\+.*$/) != null).reduce((a, b) => {
a[b] = obj[b];
return a;
}, {});
console.log(result);
You can do something like this:
var data = {
'40+30+20': {
name: "john"
},
'41+31+20': {
name: "eli"
}
};
var search = '30';
var r = Object.keys(data).filter(function(key) {
return key.split('+').some(function(p) {
return p === search;
});
}).map(function(key) {
var o = {};
o[key] = data[key];
return o;
});
console.log(r);
Try with the filter function and a regular expression:
var myObj = {'40+30+20': { name: "john" }, '41+31+20': { name: "eli" } };
function filterByStreet(obj, streetId) {
var filteredKeys = Object.keys(obj).filter((key) => {
var patt = new RegExp("[^+]+[+]" + streetId + "[+][0-9]+");
return patt.test(key);
});
var outObj = {};
for(filteredKey of filteredKeys) {
outObj[filteredKey] = obj[filteredKey];
}
return outObj;
}
var filteredObj = filterByStreet(myObj, 30);
console.log(filteredObj);
Related
I have two identical objects with me
let a = {
title : "developer”,
startDate:{ month :’jan’}
}
let b = {
title :{
value: ""
} ,
startDate :{month:{value:””}}
}
i need to merge dynamically these two to get object like below
let c = {
title :{
value: "developer"
} ,
startDate:{
month:{ value:” jan”}}
}
You don't require object b because it's just a replica of object a with extra 'value' property.
You can traverse the complete a object and then deep copy the value in the b object.
I wrote a recursive method for this where you can traverse to the last level of the object and copy the value in another object.
function mergeObj(sourceObj, newObj) {
Object.keys(sourceObj).forEach(key => {
if (sourceObj[key] && typeof sourceObj[key] === 'object') {
newObj[key] = {};
mergeObj(sourceObj[key], newObj[key]);
} else {
// updating properties
newObj[key] = {};
newObj[key]['value'] = sourceObj[key];
}
});
}
let a = {
title : "developer",
startDate:{ month :'jan'}
};
let b = {};
mergeObj(a,b);
console.log(b);
You probably need to start by making both object have the same structure, and then run the deep merge. lodash's merge can help you with it
const newA = Object.entries(a).reduce((newObject, [key, value]) => ({
...newObject,
[key]: { value },
}, {}))
// newA looks now like
//
// {
// title: {
// value: "developer
// }
// }
let c = _.merge(a, b); // lodash merge for deep merge. Otherwise write your own
Here is a workaround for your problem:
let a = {
title : "developer",
startDate:{ month :'jan'}
}
let b = {
title :{
value: ''
} ,
startDate :{month:{value:''}}
}
var c = {};
c.startDate = {};
c.title = {};
c.startDate.month = {};
c.startDate.month.value = a.startDate.month;
c.title.value = a.title;
console.log("Merged object",c);
You can just implement a function that does this for you. Given your example:
let a = {
title: "developer",
startDate: { month: "jan" }
};
let b = {
title: {
value: ""
},
startDate: { month: { value: "" }}
};
You can use this to get the values:
const mergeObject = (a, b) => {
b.title.value = a.title;
b.startDate.month.value = a.startDate.month;
return b;
};
If you call now say let c = mergeObject(a, b) c will be
let c = {
title: {
value: "developer"
},
startDate: {
month: { value: "jan" }}
}
Of course this function can be modified to reflect your exact needs.
I have the following function:
populateClinicRoomSelect(object) {
var selectArray = [];
var options = [];
for(var key in object) {
if(object.hasOwnProperty(key)) {
options = {
value: object[key].id,
label: object[key].RoomName,
};
selectArray = selectArray.concat(options);
}
}
return selectArray;
}
The idea is that takes two defined fields from the object array and places it in a new array. It works fine. I also have a few more functions exactly the same to this except the 'id' field and 'RoomName' field are different field names. Is there any way to pass 'id' and 'RoomName' as function variables to define them in the function?
Sure, you can pass field names as arguments and use [arg] accessors as you already do with [key]:
function populateClinicRoomSelect(object, valueField, labelField) {
var selectArray = [];
var options = [];
for(var key in object) {
if(object.hasOwnProperty(key)) {
options = {
value: object[key][valueField],
label: object[key][labelField],
};
selectArray = selectArray.concat(options);
}
}
return selectArray;
}
const object = {
a: {
id: 1,
room: 'first room'
},
b: {
id: 2,
room: 'second room'
}
}
const result = populateClinicRoomSelect(object, 'id', 'room');
console.log(result)
You mean like this?
function populateClinicRoomSelect(object, value, label) {
value = value || "id"; // defaults value to id
label = label || "RoomName"; // defaults label to RoomName
var selectArray = [];
var options = [];
for(var key in object) {
if(object.hasOwnProperty(key)) {
options = {
value: object[key][value],
label: object[key][label],
};
selectArray = selectArray.concat(options);
}
}
return selectArray;
}
let obj = { 1: { id:1, RoomName: "Blue Lounge" }, 2: { id:2, RoomName: "Red Lounge" } }
console.log(populateClinicRoomSelect(obj, 'id', 'RoomName'));
I have a nested object which consists of :
var obj = {
id: 1,
name: 'Stephen',
age: 18,
department: {
id: 1,
text: 'Operations'
}
}
So if I have a string or an array of values that match any of the values including the nested object values in the collection, it will return true. I have tried using _.includes of lodash but I don't know how I can iterate through the nested object.
_.includes(obj.department, 'Operations')
What I am trying to do is more like
_.includes(obj, ['Stephen', 'Operations']) // return true
Use recursion with Array#some to check if the value exists. Array#some returns immediately when the result of the predicate is true.
var obj = {
id: 1,
name: 'Stephen',
age: 18,
department: {
id: 1,
text: 'Operations'
}
}
function recursiveIncludes(obj) {
var values = [].slice.call(arguments, 1);
return Object.keys(obj).some(function(key) {
var current = obj[key];
if(values.indexOf(current) !== -1) {
return true;
}
if(typeof current === 'object' && current !== null) {
return recursiveIncludes.apply(null, [current].concat(values));
}
return false;
});
}
console.log('Operations: ', recursiveIncludes(obj, 'Operations'));
console.log('Moses, Stephen: ', recursiveIncludes(obj, 'Moses', 'Stephen'));
console.log('Moses, 58: ', recursiveIncludes(obj, 'Moses', 58));
Here is a recursive approach to it. It extracts all the properties of an object (the leaf properties) into an array. You can then call _.includes() on it.
var obj = {
id: 1,
name: 'Stephen',
age: 18,
department: {
id: 1,
text: 'Operations'
}
}
function objToArray(obj) {
var result = [];
for (const prop in obj) {
const value = obj[prop];
if (typeof value === 'object') {
result = result.concat(toArray(value));
}
else {
result.push(value);
}
}
return result;
}
_.includes(objToArray(obj), ['Stephen', 'Operations'])
Given an array of strings, this will check and see if the property exists recursively.
var obj = {
id: 1,
name: 'Stephen',
age: 18,
department: {
id: 1,
text: 'Operations'
}
}
function hasValues(obj, props)
{
var keys = Object.keys(obj);
for(var i = 0; i < keys.length; i++){
var item = obj[keys[i]];
// If the item is a string or number, do a comparison
if(typeof item === "string" || typeof item === "number"){
var idx = props.indexOf(item);
if(idx >= 0) props.splice(idx, 1);
// If it's an object then search the object recursively
} else if(typeof item === "object"){
hasValues(item, props);
}
}
return props.length === 0;
}
console.log(hasValues(obj, ['Stephen', 'Operations']))
console.log(hasValues(obj, [18, 1]))
console.log(hasValues(obj, [18, '13lkj4']))
You can use flatMap as a mechanism to flatten all the values taken from recursively using map inside the flatMap callback function. After obtaining all the values, we use difference to get the difference between all the values between the object and the values. Lastly, we check the resulting difference if it is empty using isEmpty.
function includesDeep(object, values) {
return _(obj)
.flatMap(function cb(v) { return _.isObject(v)? _.map(v, cb): v; })
.thru(_.partial(_.difference, values))
.isEmpty();
}
var result = includesDeep(obj, ['Stephen', 'Operations']);
var obj = {
id: 1,
name: 'Stephen',
age: 18,
department: {
id: 1,
text: 'Operations'
}
};
function includesDeep(object, values) {
return _(obj)
.flatMap(function cb(v) { return _.isObject(v)? _.map(v, cb): v; })
.thru(_.partial(_.difference, values))
.isEmpty();
}
var result = includesDeep(obj, ['Stephen', 'Operations']);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>
the tests shows that you can't check multi-values & value in-depth with lodash includes,so you must write a function for yourself.
Your solution
describe('includes', () => {
var value = {
foo: 'bar',
fuzz: 'buzz',
value2: {
key: 'value'
}
};
function includes(collection, values) {
return [].concat(values).every((value) => {
return Object.keys(collection).some((key) => {
let it = collection[key];
return typeof it == 'object' ? includes(it, value) : _.includes(it, value);
})
});
}
it('check single value', () => {
expect(includes(value, 'bar')).toBe(true);
expect(includes(value, 'baz')).toBe(false);
});
it('check multi values', () => {
expect(includes(value, ['bar', 'buzz'])).toBe(true);
expect(includes(value, ['baz', 'buzz'])).toBe(false);
});
it('check value in depth', () => {
expect(includes(value, 'value')).toBe(true);
expect(includes(value, 'no-exists')).toBe(false);
});
});
Test
describe('includes', () => {
var value = {
foo: 'bar',
fuzz: 'buzz',
value2: {
key: 'value'
}
};
it('check single value', () => {
expect(_.includes(value, 'bar')).toBe(true);
expect(_.includes(value, 'baz')).toBe(false);
});
it('check multi values', () => {
expect(_.includes(value, ['bar', 'buzz'])).toBe(false);
expect(_.includes(value, ['baz', 'buzz'])).toBe(false);
});
it('check value in depth', () => {
expect(_.includes(value, 'value')).toBe(false);
});
});
function includes(collection, values) {
return [].concat(values).every(function (value) {
return Object.keys(collection).some(function (key) {
var it = collection[key];
return (typeof it == 'object') ? includes(it, value) : _.includes(it, value);
});
});
}
var obj = {
id: 1,
name: 'Stephen',
age: 18,
department: {
id: 1,
text: 'Operations'
}
};
var tests=[
"Operations",
"Non-Existing Value",
['Stephen', 'Operations'],
['Stephen', 'Non-Existing Value'],
];
tests.forEach(function(test){
console.log("includes(obj,"+JSON.stringify(test)+") => "+ includes(obj,test));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
In this stackoverflow thread, i learnt you can get a object path via a simple string.
Accessing nested JavaScript objects with string key
consider the following:
var person = { name: "somename", personal: { weight: "150", color: "dark" }};
var personWeight = deep_value(person,"personal.weight");
I an trying to construct an array of the object values who are not of type 'object' from my 'person' object.
Hence the array would look like:
[['name', []],['personal.weight', []],['personal.color', []]];
I want them to look in that form because i have further use for it down the road.
That's what I've tried:
var toIterate = { name: "somename", personal: { age: "19", color: "dark" } }
var myArray = [];
$.each(toIterate, recursive);
function recursive(key, value) {
if (key !== null) {
myArray.push([key, []]);
}
else {
$.each(value, recursive);
}
}
console.log(myArray);
Just use recursion to walk the object.
var person = {
name: "somename",
personal: {
weight: "150",
color: "dark",
foo: {
bar: 'bar',
baz: 'baz'
},
empty: {
}
}
};
// however you want to do this
var isobject = function(x){
return Object.prototype.toString.call(x) === '[object Object]';
};
var getkeys = function(obj, prefix){
var keys = Object.keys(obj);
prefix = prefix ? prefix + '.' : '';
return keys.reduce(function(result, key){
if(isobject(obj[key])){
result = result.concat(getkeys(obj[key], prefix + key));
}else{
result.push(prefix + key);
}
return result;
}, []);
};
var keys = getkeys(person);
document.body.innerHTML = '<pre>' + JSON.stringify(keys) + '</pre>';
Then use Array.prototype.map to massage the array of keys into your preferred format.
Note the behaviour with person.personal.empty.
This does seem like a strange way to store an object's keys. I wonder what your 'further use for it down the road' is.
This is what worked for me. Note that, a raw map is created first and then mapped to an join the items in the Array with ..
var toIterate = {
name: "somename",
personal: {
age: "19",
color: "dark"
}
};
console.log(getObjPath(toIterate).map(item => item.join('.')));
function isObject(x) {
return Object.prototype.toString.call(x) === '[object Object]';
};
function getObjPath(obj, pathArray, busArray) {
pathArray = pathArray ? pathArray : [];
if (isObject(obj)) {
for (key in obj) {
if (obj.hasOwnProperty(key)) {
if (isObject(obj[key])) {
busArray = busArray ? bussArray : [];
busArray.push(key);
getObjPath(obj[key], pathArray, busArray);
} else {
if (busArray) {
pathArray.push(busArray.concat([key]));
} else {
pathArray.push([key]);
}
}
}
}
}
return pathArray;
}
Good Luck...
I found the following solution on github.
https://github.com/mariocasciaro/object-path
{"document":
{"people":[
{"name":["Harry Potter"],"age":["18"],"gender":["Male"]},
{"name":["hermione granger"],"age":["18"],"gender":["Female"]},
]}
}
From this JSON example, I would like to get the keys such as name, age, gender for each people.
How to do this?
I use Object.keys which is built into JavaScript Object, it will return an array of keys from given object MDN Reference
var obj = {name: "Jeeva", age: "22", gender: "Male"}
console.log(Object.keys(obj))
Try this
var s = {name: "raul", age: "22", gender: "Male"}
var keys = [];
for(var k in s) keys.push(k);
Here keys array will return your keys ["name", "age", "gender"]
var input = {"document":
{"people":[
{"name":["Harry Potter"],"age":["18"],"gender":["Male"]},
{"name":["hermione granger"],"age":["18"],"gender":["Female"]},
]}
}
var keys = [];
for(var i = 0;i<input.document.people.length;i++)
{
Object.keys(input.document.people[i]).forEach(function(key){
if(keys.indexOf(key) == -1)
{
keys.push(key);
}
});
}
console.log(keys);
ES6 of the day here;
const json_getAllKeys = data => (
data.reduce((keys, obj) => (
keys.concat(Object.keys(obj).filter(key => (
keys.indexOf(key) === -1))
)
), [])
)
And yes it can be written in very long one line;
const json_getAllKeys = data => data.reduce((keys, obj) => keys.concat(Object.keys(obj).filter(key => keys.indexOf(key) === -1)), [])
EDIT: Returns all first order keys if the input is of type array of objects
var jsonData = { Name: "Ricardo Vasquez", age: "46", Email: "Rickysoft#gmail.com" };
for (x in jsonData) {
console.log(x +" => "+ jsonData[x]);
alert(x +" => "+ jsonData[x]);
}
This function should return an array of ALL the keys (i.e. the key names) in a JSON object including nested key/value pairs.
function get_all_json_keys(json_object, ret_array = []) {
for (json_key in json_object) {
if (typeof(json_object[json_key]) === 'object' && !Array.isArray(json_object[json_key])) {
ret_array.push(json_key);
get_all_json_keys(json_object[json_key], ret_array);
} else if (Array.isArray(json_object[json_key])) {
ret_array.push(json_key);
first_element = json_object[json_key][0];
if (typeof(first_element) === 'object') {
get_all_json_keys(first_element, ret_array);
}
} else {
ret_array.push(json_key);
}
}
return ret_array
}
Using this function on the OP's original object
const op_object =
{
"document":{
"people":[
{
"name":[
"Harry Potter"
],
"age":[
"18"
],
"gender":[
"Male"
]
},
{
"name":[
"hermione granger"
],
"age":[
"18"
],
"gender":[
"Female"
]
}
]
}
}
var all_keys = [];
function get_all_json_keys(json_object, ret_array = []) {
for (json_key in json_object) {
if (typeof(json_object[json_key]) === 'object' && !Array.isArray(json_object[json_key])) {
ret_array.push(json_key);
get_all_json_keys(json_object[json_key], ret_array);
} else if (Array.isArray(json_object[json_key])) {
ret_array.push(json_key);
first_element = json_object[json_key][0];
if (typeof(first_element) === 'object') {
get_all_json_keys(first_element, ret_array);
}
} else {
ret_array.push(json_key);
}
}
return ret_array
}
get_all_json_keys(op_object, all_keys);
console.log(all_keys);
should yield
[ 'document', 'people', 'name', 'age', 'gender' ]
Note: This will return a unique list of all key names.
We must "parse" our jsonObject
console.log('{"key0":"value0", "key1":"value1"}');
var jsonObject = JSON.parse('{"key0":"value0", "key1":"value1"}')
Object.keys(jsonObject).forEach(key => {
console.log(jsonObject[key]); //values
console.log(key); //keys
})