JavaScript - iterate through object and change nested properties - javascript

This is an object to be processed:
var q = {
email: {contains: "noname#hotmail.com"},
name: {contains: "someuser"}
};
I would like to go through each key of q and if the corresponding value is an object that has the property contains then replace it with $regex.

Related information can be found here: JavaScript: Object Rename Key
You can try the following way:
var q = {
email: {contains: "noname#hotmail.com"},
name: {contains: "someuser"}
};
for(var k in q){
if(q[k].hasOwnProperty('contains')){
Object.defineProperty(q[k], '$regex',
Object.getOwnPropertyDescriptor(q[k], 'contains'));
delete q[k]['contains'];
}
}
console.log(q);

for(const obj of Object.values(q)) {
obj.$regex = obj.contains;
delete obj.contains;
}
Just go over all values inside q and copy the contains property into the $regex property.

To iterate over object keys first you have to fetch them, here is one simple approach
const keys = Object.keys(q); // ["email", "name"]
Now iterate over the array which we got and perform regex testing;
keys.forEach(key => {
let value = q[key].contains;
// create $regex and assign value
// remove .contains
})

You can loop through the objects and first put current value of contains property in $regex and then delete the contains property.
Below is working code:
var q = {
email: {
contains: "noname#hotmail.com"
},
name: {
contains: "someuser"
}
};
for (var i of Object.values(q)) {
if (i.hasOwnProperty("contains")) {
i.$regex = i.contains;
delete i.contains;
}
}
console.log(q);

var q = {
email: {contains: "noname#hotmail.com"},
name: {contains: "someuser"}
};
Object.keys(q).forEach(k => {
if (typeof q[k].contains != 'undefined'){
q[k].$regex = q[k].contains;
delete q[k].contains;
}
})
console.log(q);
Other version using Es 6 features
const renameProp = (
oldProp,
newProp,
{ [oldProp]: old, ...others }
) => {
return {
[newProp]: old,
...others
};
};
let q = {
email: {contains: "noname#hotmail.com"},
name: {contains: "someuser"}
};
let newObj = {}
for (let propName in q) {
newObj[propName] = renameProp("contains","$regex",q[propName])
}
console.log(newObj)

var q = {
email: {
contains: "noname#hotmail.com"
},
name: {
contains: "someuser"
},
asdf: "asdf"
};
Object.keys(q).forEach(function(item, index) {
if (typeof q[item] == "object" && q[item].contains) {
q[item].$regex = q[item].contains;
delete q[item].contains;
}
})

Related

Add item into array instead of overriding the current value with the new value

I'm trying to figure out how to add new items into array instead of overriding the current value with the new value. I'm using .push() which should add the item every time it maps through the array. Any Ideas?
const searchChips = [
{value: "string"}, {value: "test"}
];
const query = {
bool: {
filter: []
}
};
const searchQuery = {
query_string: {
query: ""
}
};
searchChips.map(chip => {
console.log(chip);
const key = "query";
searchQuery.query_string[key] = chip.value;
query.bool.filter.push(searchQuery);
});
console.log(query);
You are inserting the same query since you are dealing with the same exact reference to the searchQuery. Instead of this try having it as a function which returns an object:
const searchChips = [{
value: "string"
}, {
value: "test"
}];
const query = {
bool: {
filter: []
}
};
let sq = (query) => ({
query_string: {query}
});
searchChips.map(chip => query.bool.filter.push(sq(chip.value)));
console.log(query);
This will return to you the 2 filters each with different values for query_string since now the function will return an entirely new object instead of you dealing with the same reference.
The problem seems to be that you are pushing into query.bool.filter outside the .map() function. Try this.
const searchChips = [{ value: "string" }, { value: "test" }];
const query = {
bool: {
filter: []
}
};
searchChips.forEach(chip => {
const key = "query";
const searchQuery = {
query_string: {
query: ""
}
};
searchQuery.query_string[key] = chip.value;
query.bool.filter.push(searchQuery);
});
console.log(JSON.stringify(query));

How to get proprety value of object from parent object

I have object in this structure:
obj = {
user: { name: 'jeterson' },
title: 'I am a test'
}
I have one key with value: user.name.
I have trying get value like this: obj[key], meaning obj['user.name']. It not works, only works for obj.title.
My object have many values that are also objects, and i want get value like this:
myobject[mykey]
It is possible get value from property object like above ?
You can access it with:
obj['user']['name']
Or alternatively:
obj.user.name
If you want to get from a key like "user.name" to the value, you woulr have to do some logic yourself. You could hack something together like this:
let obj = {
user: {
name: 'jeterson'
},
title: 'I am a test'
}
let key = 'user.name';
let keys = key.split('.');
let res = obj;
while (keys.length > 0 && res) {
let k = keys.shift();
res = res[k];
}
console.log(res) // "jeterson"
When the keys do not match, res holds undefined.
You've got multiple solutions to access an element of an object with its keys:
var obj = {
user: { name: 'jeterson' },
title: 'I am a test'
}
console.log(obj['user']['name']);
console.log(obj['user'].name);
console.log(obj.user['name']);
console.log(obj.user.name);
But you can't do it easily with a variable key = 'user.name'.
If you need to use a variable containing the nested-keys, you could create a function.
Updated answer: An amazingly short way to achieve it is to use .reduce():
// My function
function obj_tree_key(obj, path) {
return path.split('.').reduce((accu, val) => accu[val] || 'Not found', obj);
}
var obj1 = {
user: {
name: 'jeterson'
},
title: 'I am a test'
}
console.log(obj_tree_key(obj1, 'user.name')); // Outputs "jeterson"
// Here is an example with error:
var obj2 = {
user: {
nameeeee: 'jeterson'
},
title: 'I am a test'
}
console.log(obj_tree_key(obj2, 'user.name'));
Old answer: Use a for to loop through the keys and reduce the oject:
// My function
function obj_tree_key(obj, tree_key) {
var result = obj;
var keys = tree_key.split('.');
for (var i = 0; i < keys.length; i++) {
result = result[keys[i]] || 'Not found'; // Error handling
}
return result;
}
var obj1 = {
user: {
name: 'jeterson'
},
title: 'I am a test'
}
console.log(obj_tree_key(obj1, 'user.name')); // Outputs "jeterson"
// Here is an example with error:
var obj2 = {
user: {
nameeeee: 'jeterson'
},
title: 'I am a test'
}
console.log(obj_tree_key(obj2, 'user.name'));
Hope it helps.
first get the user, then the name:
obj['user']['name']
or
obj.user.name
You can also use
obj.user.name
You could access it using
console.log(obj.user.name);
You can do it in 2 way:
obj['user']['name']
or
obj.user.name

How to split a doted string and retrive the data from object by notation?

At present, I do this approach:
var obj = {
sender: {
name: "tech"
}
}
var str = "sender.name".split('.');
console.log( obj[str[0]][str[1]] ); //getting update as 'Tech'
In the above I use obj[str[0]][str[1]] for just 2 step, this is works fine. In case if I received a long node parent and child this approach not going to work.
Instead is there any correct dynamic way to do this?
You can use array#reduce to navigate through each key.
var obj = { sender: { name: "tech" } };
var str = "sender.name".split('.').reduce((r,k) => r[k],obj);
console.log(str);
You can use reduce:
var obj = {
foo: {
bar: {
baz: {
sender: {
name: "tech"
}
}
}
}
}
const props = "foo.bar.baz.sender.name".split('.');
const val = props.reduce((currObj, prop) => currObj[prop], obj);
console.log(val);
You could split the string and reduce the path for the result. The function uses a default object for missing or not given properties.
function getValue(object, path) {
return path
.split('.')
.reduce(function (o, k) { return (o || {})[k]; }, object);
}
var obj = { sender: { name: "tech" } },
str = "sender.name";
console.log(getValue(obj, str));
You should be looking into libraries such as "https://lodash.com/"
https://lodash.com/docs/4.17.10
Use _.get : https://lodash.com/docs/4.17.10#get
You can simply write _.get(obj, 'sender.name', 'default') and you will get the value as you expect

How to turn this array into a JavaScript object?

The following code loops through a JavaScript object and collects only the properties that are arrays:
const building = this.building
let panoramaList = []
for (let key in building) {
const panoramas = building[key]
if (Array.isArray(panoramas)) {
panoramaList.push({ [key]: panoramas })
}
}
console.log(panoramaList)
In other words, it takes this:
{
name: '',
description: ''.
livingroom: Array[0],
study: Array[1],
bedroom: Array[0]
}
and turns it into this:
[
{ livingroom: Array[0] },
{ study: Array[1] },
{ bedroom: Array[0] }
]
However, what I need to produce is this:
{
livingroom: Array[0],
study: Array[1],
bedroom: Array[0]
}
How to accomplish that?
Change this :
const building = this.building
let panoramaList = []
for (let key in building) {
const panoramas = building[key]
if (Array.isArray(panoramas)) {
panoramaList.push({ [key]: panoramas })
}
}
console.log(panoramaList)
to this :
const building = this.building
let panoramaList = {}
for (let key in building) {
const panoramas = building[key]
if (Array.isArray(panoramas)) {
panoramaList[key]=panoramas
}
}
console.log(panoramaList)
Use Object.keys and try something like this:
var input = {} //...your input array
var keys = Object.keys(input);
var result = {};
keys.forEach(function (key) {
if (Array.isArray(input[key])) {
result[key] = input[key];
}
});
try this
var output = Object.keys(building).map(function(val){ return { val : building[val] } });
For the final output
var panoramaList = {}
Object.keys(building).forEach(function(val){
if ( Array.isArray(building[val] )
{
panoramaList[val] = building[val];
}
});
Make sure to define panoramaList as an object.
This works
var arrays = {
name: '',
description: '',
livingroom: ['1','www'],
study: ['2','sss'],
bedroom: ['3','aaa'],
Kitchen: ['4','bbb'],
}
const building = arrays
let panoramaList = {};
for (let key in building) {
const panoramas = building[key]
if (Array.isArray(panoramas)) {
panoramaList[key] = panoramas;
}
}
console.log(panoramaList);
https://jsbin.com/paqebupiva/1/edit?js,console,output
Rather than building a new object, you might just need to delete the unwanted properties from the object that you have:
var data = {
name: '',
description: '',
livingroom: [],
study: [1],
bedroom: [0]
};
Object.keys(data).forEach(function(key) {
if (!Array.isArray(data[key])) delete data[key];
})
document.write(JSON.stringify(data));

Convert javascript object camelCase keys to underscore_case

I want to be able to pass any javascript object containing camelCase keys through a method and return an object with underscore_case keys, mapped to the same values.
So, I have this:
var camelCased = {firstName: 'Jon', lastName: 'Smith'}
And I want a method to output this:
{first_name: 'Jon', last_name: 'Jon'}
What's the fastest way to write a method that takes any object with any number of key/value pairs and outputs the underscore_cased version of that object?
Here's your function to convert camelCase to underscored text (see the jsfiddle):
function camelToUnderscore(key) {
return key.replace( /([A-Z])/g, "_$1").toLowerCase();
}
console.log(camelToUnderscore('helloWorldWhatsUp'));
Then you can just loop (see the other jsfiddle):
var original = {
whatsUp: 'you',
myName: 'is Bob'
},
newObject = {};
function camelToUnderscore(key) {
return key.replace( /([A-Z])/g, "_$1" ).toLowerCase();
}
for(var camel in original) {
newObject[camelToUnderscore(camel)] = original[camel];
}
console.log(newObject);
If you have an object with children objects, you can use recursion and change all properties:
function camelCaseKeysToUnderscore(obj){
if (typeof(obj) != "object") return obj;
for(var oldName in obj){
// Camel to underscore
newName = oldName.replace(/([A-Z])/g, function($1){return "_"+$1.toLowerCase();});
// Only process if names are different
if (newName != oldName) {
// Check for the old property name to avoid a ReferenceError in strict mode.
if (obj.hasOwnProperty(oldName)) {
obj[newName] = obj[oldName];
delete obj[oldName];
}
}
// Recursion
if (typeof(obj[newName]) == "object") {
obj[newName] = camelCaseKeysToUnderscore(obj[newName]);
}
}
return obj;
}
So, with an object like this:
var obj = {
userId: 20,
userName: "John",
subItem: {
paramOne: "test",
paramTwo: false
}
}
newobj = camelCaseKeysToUnderscore(obj);
You'll get:
{
user_id: 20,
user_name: "John",
sub_item: {
param_one: "test",
param_two: false
}
}
es6 node solution below. to use, require this file, then pass object you want converted into the function and it will return the camelcased / snakecased copy of the object.
const snakecase = require('lodash.snakecase');
const traverseObj = (obj) => {
const traverseArr = (arr) => {
arr.forEach((v) => {
if (v) {
if (v.constructor === Object) {
traverseObj(v);
} else if (v.constructor === Array) {
traverseArr(v);
}
}
});
};
Object.keys(obj).forEach((k) => {
if (obj[k]) {
if (obj[k].constructor === Object) {
traverseObj(obj[k]);
} else if (obj[k].constructor === Array) {
traverseArr(obj[k]);
}
}
const sck = snakecase(k);
if (sck !== k) {
obj[sck] = obj[k];
delete obj[k];
}
});
};
module.exports = (o) => {
if (!o || o.constructor !== Object) return o;
const obj = Object.assign({}, o);
traverseObj(obj);
return obj;
};
Came across this exact problem when working between JS & python/ruby objects. I noticed the accepted solution is using for in which will throw eslint error messages at you ref: https://github.com/airbnb/javascript/issues/851 which alludes to rule 11.1 re: use of pure functions rather than side effects ref:https://github.com/airbnb/javascript#iterators--nope
To that end, figured i'd share the below which passed the said rules.
import { snakeCase } from 'lodash'; // or use the regex in the accepted answer
camelCase = obj => {
const camelCaseObj = {};
for (const key of Object.keys(obj)){
if (Object.prototype.hasOwnProperty.call(obj, key)) {
camelCaseObj[snakeCase(key)] = obj[key];
}
}
return camelCaseObj;
};
Marcos Dimitrio posted above with his conversion function, which works but is not a pure function as it changes the original object passed in, which may be an undesireable side effect. Below returns a new object that doesn't modify the original.
export function camelCaseKeysToSnake(obj){
if (typeof(obj) != "object") return obj;
let newObj = {...obj}
for(var oldName in newObj){
// Camel to underscore
let newName = oldName.replace(/([A-Z])/g, function($1){return "_"+$1.toLowerCase();});
// Only process if names are different
if (newName != oldName) {
// Check for the old property name to avoid a ReferenceError in strict mode.
if (newObj.hasOwnProperty(oldName)) {
newObj[newName] = newObj[oldName];
delete newObj[oldName];
}
}
// Recursion
if (typeof(newObj[newName]) == "object") {
newObj[newName] = camelCaseKeysToSnake(newObj[newName]);
}
}
return newObj;
}
this library does exactly that: case-converter
It converts snake_case to camelCase and vice versa
const caseConverter = require('case-converter')
const snakeCase = {
an_object: {
nested_string: 'nested content',
nested_array: [{ an_object: 'something' }]
},
an_array: [
{ zero_index: 0 },
{ one_index: 1 }
]
}
const camelCase = caseConverter.toCamelCase(snakeCase);
console.log(camelCase)
/*
{
anObject: {
nestedString: 'nested content',
nestedArray: [{ anObject: 'something' }]
},
anArray: [
{ zeroIndex: 0 },
{ oneIndex: 1 }
]
}
*/
following what's suggested above, case-converter library is deprectaed, use snakecase-keys instead -
https://github.com/bendrucker/snakecase-keys
supports also nested objects & exclusions.
Any of the above snakeCase functions can be used in a reduce function as well:
const snakeCase = [lodash / case-converter / homebrew]
const snakeCasedObject = Object.keys(obj).reduce((result, key) => ({
...result,
[snakeCase(key)]: obj[key],
}), {})
jsfiddle
//This function will rename one property to another in place
Object.prototype.renameProperty = function (oldName, newName) {
// Do nothing if the names are the same
if (oldName == newName) {
return this;
}
// Check for the old property name to avoid a ReferenceError in strict mode.
if (this.hasOwnProperty(oldName)) {
this[newName] = this[oldName];
delete this[oldName];
}
return this;
};
//rename this to something like camelCase to snakeCase
function doStuff(object) {
for (var property in object) {
if (object.hasOwnProperty(property)) {
var r = property.replace(/([A-Z])/, function(v) { return '_' + v.toLowerCase(); });
console.log(object);
object.renameProperty(property, r);
console.log(object);
}
}
}
//example object
var camelCased = {firstName: 'Jon', lastName: 'Smith'};
doStuff(camelCased);
Note: remember to remove any and all console.logs as they aren't needed for production code

Categories