Normalise Javascript object - javascript

I have a json object with objects inside of it
such as user: {"name": "tim"} and would like a way to turn that in "user.name": 'tim'
I've tried: Javascript Recursion normalize JSON data
Which does not return the result I want, also tried some packages, no luck

You can use a recursive approach to flatten nested objects, by concatenating their keys, as shown below:
const flattenObject = (obj) => {
const flatObject = {};
Object.keys(obj).forEach((key) => {
const value = obj[key];
if (typeof value === 'object') {
const flatNestedObject = flattenObject(value);
Object.keys(flatNestedObject).forEach((nestedKey) => {
flatObject[`${key}.${nestedKey}`] = flatNestedObject[nestedKey];
});
} else {
flatObject[key] = value;
}
});
return flatObject;
};
const obj = {
user: { name: 'tim' },
};
console.log(flattenObject(obj));
This solution works for any amount of levels.
If your environment does not support Object.keys, you can use for..in instead:
const flattenObject = (obj) => {
const flatObject = {};
for (const key in obj) {
if (!obj.hasOwnProperty(key)) continue;
const value = obj[key];
if (typeof value === 'object') {
const flatNestedObject = flattenObject(value);
for (const nestedKey in flatNestedObject) {
if (!flatNestedObject.hasOwnProperty(nestedKey)) continue;
flatObject[`${key}.${nestedKey}`] = flatNestedObject[nestedKey];
}
} else {
flatObject[key] = value;
}
}
return flatObject;
};
const obj = {
user: { name: 'tim' },
};
console.log(flattenObject(obj));

This can easily be done like so:
const myObject = {
user: {
firstname: "john",
lastname: "doe"
}
}
function normalize(suppliedObject = {}) {
const newObject = {};
for (const key of Object.keys(suppliedObject)) {
for (const subKey of Object.keys(suppliedObject[key])) {
newObject[`${key}.${subKey}`] = suppliedObject[key][subKey];
}
}
return newObject;
}
console.log(normalize(myObject));
Be aware that this only normalizes 1 level deep. You can extend the function to normalize all the way down to the last level.

Related

how to export a variable from a constant in javascript

I'm currently converting code from Common JS to ES6 and ran into an issue I'm unable to exprort columnset and values variables. Any tips or tricks for this?
export const multipleColumnSet = (object) => {
if (typeof object !== 'object') {
throw new Error('Invalid input');
}
const keys = Object.keys(object);
const values = Object.values(object);
columnSet = keys.map(key => `${key} = ?`).join(', ');
return {
columnSet,
values
}
};
However When I try to use it says undefined.
import { multipleColumnSet } from '../utils/common.utils.js';
class UserModel {
tableName = 'user'
findUser = async (params) => {
const { columnSet, values } = multipleColumnSet(params)
const sql = `SELECT * FROM ${this.tableName} WHERE ${columnSet}`
const result = await query(sql, [...values])
return result[0]
}
}
I have added the Common JS I've converted from.
exports.getPlaceholderStringForArray = (arr) => {
if (!Array.isArray(arr)) {
throw new Error('Invalid input');
}
// if is array, we'll clone the arr
// and fill the new array with placeholders
const placeholders = [...arr];
return placeholders.fill('?').join(', ').trim();
}
exports.multipleColumnSet = (object) => {
if (typeof object !== 'object') {
throw new Error('Invalid input');
}
const keys = Object.keys(object);
const values = Object.values(object);
columnSet = keys.map(key => `${key} = ?`).join(', ');
return {
columnSet,
values
}
}

Extracting values out of an array of objects?

I am trying to extract id from the below array of objects and so far I am able to give it a go with the below code but it is showing undefined and cannot get id , would you please check the code and adjust to get id out?
const array = [{
contact: {
id: 1,
email: 'roar#gmail.com',
},
date: '2/4/22'
},
{
contact: {
id: 2,
email: 'grr#gmail.com',
},
date: '2/4/22'
}
]
function extractValue(arr, prop) {
let extractedValue = [];
for (let i = 0; i < arr.length; ++i) {
// extract value from property
extractedValue.push(arr[i][prop]);
}
return extractedValue;
}
const result = extractValue(array, 'contact.id');
console.log(result);
A good way to do this is the Array Map method
This will get all the id's from your array
const result = array.map((val) => val.contact.id)
const extractValue = (array, path) => {
const [first, second] = path.split('.')
if (second) return array.map(obj => obj[first][second])
return array.map(obj => obj[first])
}
const res = extractValue(array, 'contact.id')
console.log(res)
// => [ 1, 2 ]
this will support single and double level nested results
function find(val, arr) {
for (let x of arr)
val = val[x];
return val;
}
function extractValue(arr, prop) {
return array.map(x => find(x, prop.split(".")))
}

search array within a object in javascript / typescript

I want to find the first array in an object in Javascript. However my functions cause an error:
el is undefined
el contains the object that looks like this:
data = {
foo: {
bar: [{object a},
{object b},
{object c}
]
}
}
let el = data;
el = this.searchArray(el);
el.forEach(element => {
console.log(element);
let siblingData = this.injectFilterParameters(element);
});
//here is unimportant code
searchArray(obj) {
if (Array.isArray(obj)) {
return obj;
} else {
Object.keys(obj).forEach(key => {
if (Array.isArray(obj[key])) {
return obj[key];
} else {
return this.searchArray(obj[key]);
}
})
}
}
const data = {
foo: {
bar: [
{ object: 'a' },
{ object: 'b' },
{ object: 'c' }
]
}
}
console.log(findArray(data))
function findArray(data: unknown): unknown[] | undefined {
if (Array.isArray(data)) {
return data
}
if (typeof data !== 'object') {
return undefined
}
const object = data as Record<string, unknown>
for (const key of Object.keys(object)) {
const value = object[key]
const valueSearchResult = findArray(value)
if (valueSearchResult != undefined) {
return valueSearchResult
}
}
return undefined
}

add elements to object - javascript

I'm trying to build an object given an array of objects
const someArray = [
{
name: 'x.y',
value: 'Something for Y'
},
{
name: 'x.a.z',
value: 'Something for Z'
}
]
to look like this
{
x: {
a: {
z: 'Something for Z'
},
y: 'Something for Y'
}
}
I have this code
const buildObj = data => {
let obj = {}
data.forEach(item => {
let items = item.name.split('.')
items.reduce((acc, val, idx) => {
acc[val] = (idx === items.length - 1) ? item.value : {}
return acc[val]
}, obj)
})
return obj
}
buildObj(someArray)
but it doesn't include the y keypair. what's missing?
What you want to do is create an object, then for each dotted path, navigate through the object, creating new object properties as you go for missing parts, then assign the value to the inner-most property.
const someArray = [{"name":"x.y","value":"Something for Y"},{"name":"x.a.z","value":"Something for Z"}]
const t1 = performance.now()
const obj = someArray.reduce((o, { name, value }) => {
// create a path array
const path = name.split(".")
// extract the inner-most object property name
const prop = path.pop()
// find or create the inner-most object
const inner = path.reduce((i, segment) => {
// if the segment property doesn't exist or is not an object,
// create it
if (typeof i[segment] !== "object") {
i[segment] = {}
}
return i[segment]
}, o)
// assign the value
inner[prop] = value
return o
}, {})
const t2 = performance.now()
console.info(obj)
console.log(`Operation took ${t2 - t1}ms`)
.as-console-wrapper { max-height: 100% !important; }
This is ABD at this point but I did it with a recursive builder of the path.
const someArray = [
{
name: 'x.y',
value: 'Something for Y'
},
{
name: 'x.a.z',
value: 'Something for Z'
}
]
const createPath = (path, value) => {
if(path.length === 1){
let obj = {}
obj[path.shift()] = value
return obj
}
let key = path.shift();
let outObject = {}
outObject[key] = { ...createPath(path, value) }
return outObject
}
const createObjectBasedOnDotNotation = (arr) => {
let outObject = {}
for(let objKey in arr){
const { name, value } = arr[objKey];
let object = createPath(name.split("."), value)
let mainKey = Object.keys(object)[0];
!outObject[mainKey] ?
outObject[mainKey] = {...object[mainKey]} :
outObject[mainKey] = {
...outObject[mainKey],
...object[mainKey]
}
}
return outObject
}
console.log(createObjectBasedOnDotNotation(someArray))
Here's an option using for loops and checking nesting from the top down.
const someArray = [
{
name: 'x.y',
value: 'Something for Y'
},
{
name: 'x.a.z',
value: 'Something for Z'
}
]
function parseArr(arr) {
const output = {};
for (let i = 0; i < arr.length; i++) {
const {name, value} = arr[i];
const keys = name.split('.');
let parent = output;
for (let j = 0; j < keys.length; j++) {
const key = keys[j];
if (!parent.hasOwnProperty(key)) {
parent[key] = j === keys.length - 1 ? value : {};
}
parent = parent[key];
}
}
return output;
}
console.log(parseArr(someArray));

What is better performance using assigning objects?

There is an object this.visitors:
doFilter() {
this.visitorsCopy = this.visitors;
this.visitorsCopy = this.visitors.filter((p: IVisitor) => {
})
}
This function takes initial object and makes filter, each time when I call doFilter it filters by initial object. So, how to optimize this approach?
You can try this.
let testObj = { name: "jack", age: 23, test: 4 };
function filter(obj, ...keys) {
let objstr = JSON.stringify(obj);
let tempObj = null;
try {
tempObj = JSON.parse(objstr, (key, value) => {
if (!keys.includes(key)) return value;
else return;
});
} catch (error) {
console.log(error);
}
return tempObj;
}
let result = filter(testObj, "name");
console.log(result);//{ "age": 23, "test": 4 }

Categories