How to get key1 by using uniquevalue1 from the following object? If that's possible, how to get key by othervalues in 'an array'?
{
'key1': {
anarray: ['othervalues '],
value: 'uniquevalue1'
},
'key2': {
value: 'uniquevalue2',
anarray: ['othervalues ']
}
}
You could .find a key-value pair:
const [key] = Object.entries(input)
.find(([, { value }]) => value === "uniquevalue1");
Here's an example on how you can find the key by value.
let arr = { 'key1': { anarray: [ 'othervalues ' ], value: 'uniquevalue1' }, 'key2': { value: 'uniquevalue2', anarray: [ 'othervalues ' ] }}
const findKeyByValue = (val) => {
for(const key in arr) {
if(arr[key].value.includes(val))
return key;
}
};
console.log(findKeyByValue('uniquevalue1'));
Matches the value which is a string or inside an array
function getKeyByValue(_json, searchValue, searchInArray=false) {
for (const [key,val] of Object.entries(_json)) {
const {anarray, value} = val;
if (searchInArray && anarray.includes(searchValue)) {
return key;
} else if (searchValue === value) {
return key;
}
}
}
var data = {
'key1': {
anarray: ['othervalues'],
value: 'uniquevalue1'
},
'key2': {
value: 'uniquevalue2',
anarray: ['othervalues']
}
};
console.log(getKeyByValue(data, 'uniquevalue1'));
console.log(getKeyByValue(data, 'othervalues', true));
Related
I got this type of object:
const obj = {
group: {
data: {
data: [
{
id: null,
value: 'someValue',
data: 'someData'
}
]
}
}
};
I need to edit this object so whenever null is in the property value,
it would be replaced with some string.
Meaning if the replacement string will be 'someId',
the expected outcome is:
const obj = {
group: {
data: {
data: [
{
id: 'someId',
value: 'someValue',
data: 'someData'
}
]
}
}
};
Closest I found were this and this but didn't manage to manipulate the solutions there to what i need.
How should I do it?
Probably running into issues with the array values. Pass in the index of the array to modify. In this case [0]
obj.group.data.data[0].id = "someId"
EDIT
This will update all null values of id inside the data array:
obj.group.data.data.forEach(o => {
if (o.id === null) {
o.id = "someId"
}
})
Another EDIT
Here is an algorithm to recursively check all deeply nested values in an object. It will compile an array of object paths where null values live. There is an included helper method to find and update the value of the object at the given path in the array. There is a demonstration of the program in the console.
const object = {
group: {
data: {
data: [
{
id: null,
value: "foo",
data: [null, "bar", [null, { stuff: null }]]
},
{
id: null,
value: null,
data: {
bar: [null]
}
},
{
id: null,
value: "foo",
data: null
},
{
id: 4,
value: "foo",
data: "bar"
},
{
id: 4,
value: "stuff",
data: null
}
]
},
attributes: null,
errors: ["stuff", null]
}
}
const inspectProperty = (key, obj, path = "") => {
if (typeof obj[key] === "object") {
if (obj[key] instanceof Array) {
return analyzeArray(obj[key], `${path ? path + "." : ""}${key}`);
}
return analyzeObj(obj[key], `${path ? path + "." : ""}${key}`);
}
return [];
};
const analyzeKey = (obj, key, path = "") => {
if (obj[key] === null) return [`${path ? path + "." : ""}${key}`];
return inspectProperty(key, obj, path).reduce((a, k) => [...a, ...k], []);
};
const analyzeObj = (obj, path = "") => {
return Object.keys(obj).map((item) => analyzeKey(obj, item, path));
};
const analyzeArray = (array, path) => {
return array.map((item, i) => analyzeKey(array, i, path));
};
const updateNullValue = (path, value) => {
let p = path.split(".");
p.reduce((accum, iter, i) => {
if (i === p.length - 1) {
accum[iter] = value;
return object;
}
return accum[iter];
}, object);
};
let nullValues = analyzeObj(object)[0]
console.log(nullValues)
nullValues.forEach((nullVal, i) => {
updateNullValue(nullVal, "hello-" + i)
})
console.log(object)
I need to convert object:
{
middleName: null,
name: "Test Name",
university: {
country: {
code: "PL"
},
isGraduated: true,
speciality: "Computer Science"
}
}
to array:
[{
key: "name",
propertyValue: "Test Name",
},
{
key: "middleName",
propertyValue: null,
},
{
key: "university.isGraduated",
propertyValue: true,
},
{
key: "university.speciality",
propertyValue: "Computer Science",
},
{
key: "university.country.code",
propertyValue: "PL"
}];
I wrote algorithm, but it's pretty dummy, how can I improve it? Important, if object has nested object than I need to write nested object via dot (e.g university.contry: "value")
let arr = [];
Object.keys(parsedObj).map((key) => {
if (parsedObj[key] instanceof Object) {
Object.keys(parsedObj[key]).map((keyNested) => {
if (parsedObj[key][keyNested] instanceof Object) {
Object.keys(parsedObj[key][keyNested]).map((keyNestedNested) => {
arr.push({ 'key': key + '.' + keyNested + '.' + keyNestedNested, 'propertyValue': parsedObj[key][keyNested][keyNestedNested] })
})
} else {
arr.push({ 'key': key + '.' + keyNested, 'propertyValue': parsedObj[key][keyNested] })
}
})
} else {
arr.push({ 'key': key, 'propertyValue': parsedObj[key] })
}
});
Thanks
A recursive function implementation.
I have considered that your object consist of only string and object as the values. If you have more kind of data types as your values, you may have to develop on top of this function.
const myObj = {
middleName: null,
name: "Test Name",
university: {
country: {
code: "PL"
},
isGraduated: true,
speciality: "Computer Science"
}
}
const myArr = [];
function convertObjectToArray(obj, keyPrepender) {
Object.entries(obj).forEach(([key, propertyValue]) => {
if (typeof propertyValue === "object" && propertyValue) {
const updatedKey = keyPrepender ? `${keyPrepender}.${key}` : key;
convertObjectToArray(propertyValue, updatedKey)
} else {
myArr.push({
key: keyPrepender ? `${keyPrepender}.${key}` : key,
propertyValue
})
}
})
}
convertObjectToArray(myObj);
console.log(myArr);
I'd probably take a recursive approach, and I'd probably avoid unnecessary intermediary arrays (though unless the original object is massive, it doesn't matter). For instance (see comments):
function convert(obj, target = [], prefix = "") {
// Loop through the object keys
for (const key in obj) {
// Only handle "own" properties
if (Object.hasOwn(obj, key)) {
const value = obj[key];
// Get the full key for this property, including prefix
const fullKey = prefix ? prefix + "." + key : key;
if (value && typeof value === "object") {
// It's an object...
if (Array.isArray(value)) {
throw new Error(`Arrays are not valid`);
} else {
// ...recurse, providing the key as the prefix
convert(value, target, fullKey);
}
} else {
// Not an object, push it to the array
target.push({key: fullKey, propertyValue: value});
}
}
}
// Return the result
return target;
}
Live Example:
const original = {
middleName: null,
name: "Test Name",
university: {
country: {
code: "PL"
},
isGraduated: true,
speciality: "Computer Science"
}
};
function convert(obj, target = [], prefix = "") {
// Loop through the object keys
for (const key in obj) {
// Only handle "own" properties
if (Object.hasOwn(obj, key)) {
const value = obj[key];
// Get the full key for this property, including prefix
const fullKey = prefix ? prefix + "." + key : key;
if (value && typeof value === "object") {
// It's an object...
if (Array.isArray(value)) {
throw new Error(`Arrays are not valid`);
} else {
// ...recurse, providing the key as the prefix
convert(value, target, fullKey);
}
} else {
// Not an object, push it to the array
target.push({key: fullKey, propertyValue: value});
}
}
}
// Return the result
return target;
}
const result = convert(original, []);
console.log(result);
.as-console-wrapper {
max-height: 100% !important;
}
Note that I've assumed the order of the array entries isn't significant. The output you said you wanted is at odds with the standard order of JavaScript object properties (yes, they have an order now; no, it's not something I suggest relying on 😀). I've gone ahead and not worried about the order within an object.
This is the most bulletproof I could do :D, without needing a global variable, you just take it, and us it wherever you want!
const test = {
middleName: null,
name: "Test Name",
university: {
country: {
code: "PL"
},
isGraduated: true,
speciality: "Computer Science"
}
};
function toPropertiesByPath(inputObj) {
let arr = [];
let initialObj = {};
const getKeys = (obj, parentK='') => {
initialObj = arr.length === 0 ? obj: initialObj;
const entries = Object.entries(obj);
for(let i=0; i<entries.length; i++) {
const key = entries[i][0];
const val = entries[i][1];
const isRootElement = initialObj.hasOwnProperty(key);
parentK = isRootElement ? key: parentK+'.'+key;
if(typeof val === 'object' && val!==null && !Array.isArray(val)){
getKeys(val, parentK);
} else {
arr.push({ key: parentK, property: val });
}
}
};
getKeys(inputObj);
return arr;
}
console.log(toPropertiesByPath(test));
I wrote a small version using recursive function and another for validation is an object.
let values = {
middleName: null,
name: "Test Name",
university: {
country: {
code: "PL"
},
isGraduated: true,
speciality: "Computer Science"
}
}
function isObject(obj) {
return obj != null && obj.constructor.name === "Object"
}
function getValues(values) {
let arrValues = Object.keys(values).map(
v => {
return { key: v, value: isObject(values[v]) ? getValues(values[v]) : values[v] };
});
console.log(arrValues);
}
getValues(values);
I have a map of objects:
"0": {
key: 'id',
value: {
name: "eval"
// other variables
}
},
"1": {
key: 'id',
value: {
name: "help"
// other variables
}
} // and so on
I need to find an element in map that's name variable is eqaul to "eval". What's the easiest way to do this?
If "map" is an array
let arr = [{key:'id', value:{ name:'eval' }}]
let item = arr.find(el => el.value.name == 'eval')
If "map" is an object
let obj = {0:{key:'id', value:{ name:'eval' }}}
let item = Object.values(obj).find(el => el.value.name == 'eval')
Use <Array>.from to convert map values to array and after filter what you want.
const map = new Map();
map.set(0, {
key: 'id',
value: {
name: "eval"
}
});
map.set(1, {
key: 'id',
value: {
name: "help"
}
});
const result = Array.from(map.values())
.filter(x => x.value.name === 'eval')[0];
console.log(result);
The good old forEach Loop can do it too.
const data = [{
key: 'id',
value: {
name: "eval"
// other variables
}
},
{
key: 'id',
value: {
name: "help"
// other variables
}
}]
let res = [];
data.forEach((el) => {
if (el.value.name === "eval") {
res.push(el);
}
})
console.log(res)
You can do this
const tmp = {
"0": {
key: "id",
value: {
name: "eval"
// other variables
}
},
"1": {
key: "id",
value: {
name: "eval"
// other variables
}
}
};
function findEval(obj, target) {
const elem = Object.keys(obj).filter(key => tmp[key].value.name === target);
return elem.map(e => obj[e]);
}
console.log(findEval(tmp, 'eval'))
but better use lodash Find property by name in a deep object
simple and best solution
const tmp = {
"0": {
key: "id",
value: {
name: "eval"
// other variables
}
},
"1": {
key: "id",
value: {
name: "eval"
// other variables
}
}
};
function findEval(obj, target) {
for (var i=0; i < Object.keys(obj).length; i++) {
if (obj[i].value.name === target) {
return obj[i].value.name;
}
}
}
console.log(findEval(tmp, 'eval'))
I trying to generate all possible paths of the given json object. Some how I generated the paths but I want my final array in a flatten manner (no nested arrays inside the final array).
I tried speading the array, but the final array contains some nested arrays. I want to have all the elements in a flatter manner.
Current op:
[
"obj",
"level1.level2.level3.key",
[
"arrayObj.one[0].name",
"arrayObj.one[0].point"
]
]
Expected:
[
"obj",
"level1.level2.level3.key",
"arrayObj.one[0].name",
"arrayObj.one[0].point"
]
Below I have attached the snippet I tried.
const allPaths = (obj, path = "") =>
Object.keys(obj).reduce((res, el) => {
if (Array.isArray(obj[el]) && obj[el].length) {
return [...res, ...obj[el].map((item, index) => {
return [...res, ...allPaths(item, `${path}${el}[${index}].`)];
})];
} else if (typeof obj[el] === "object" && obj[el] !== null) {
return [...res, ...allPaths(obj[el], `${path}${el}.`)];
}
return [...res, path + el];
}, []);
const obj = {
obj: 'sample',
level1: {
level2: {
level3: {
key: 'value'
}
}
},
arrayObj: {
one: [{
name: 'name',
point: 'point'
},
{
name: 'name2',
point: 'point2'
},
{
name: 'name2',
point: 'point2'
}
]
}
}
console.log(allPaths(obj));
UPDATE: I didn't understood the question previously correctly. Now i do. So yes the below code will solve the problem for you.
You want your object to be flattened with dots
If thats the case the below should work
const obj = {
obj: 'sample',
level1: {
level2: {
level3: {
key: 'value'
}
}
},
arrayObj: {
one: [{
name: 'name',
point: 'point'
},
{
name: 'name2',
point: 'point2'
},
{
name: 'name2',
point: 'point2'
}
]
}
}
function flatten(data, prefix) {
let result = {}
for(let d in data) {
if(typeof data[d] == 'object') Object.assign(result, flatten(data[d], prefix + '.' + d))
else result[(prefix + '.' + d).replace(/^\./, '')] = data[d]
}
return result
}
console.log(flatten(obj, ''))
I am trying to get the change object from two objects using typescript in angular.
For example
this.productPreviousCommand = {
"id": "60f910d7d03dbd2ca3b3dfd5",
"active": true,
"title": "ss",
"description": "<p>ss</p>",
"category": {
"id": "60cec05df64bde4ab9cf7460"
},
"subCategory": {
"id": "60cec18c56d3d958c4791117"
},
"vendor": {
"id": "60ced45b56d3d958c479111c"
},
"type": "load_product_success"
}
model = {
"active": true,
"title": "ss",
"description": "<p>ss sss</p>",
"category": "60cec05df64bde4ab9cf7460",
"subCategory": "60cec18c56d3d958c4791117",
"vendor": "60ced45b56d3d958c479111c",
"tags": []
}
Now the difference between two objects are description: "<p>hello hello 1</p>". So I want to return {description: "<p>hello hello 1</p>"}
I used lodash https://github.com/lodash/lodash
import { transform, isEqual, isObject, isArray} from 'lodash';
function difference(origObj, newObj) {
function changes(newObj, origObj) {
let arrayIndexCounter = 0
return transform(newObj, function (result, value, key) {
if (!isEqual(value, origObj[key])) {
let resultKey = isArray(origObj) ? arrayIndexCounter++ : key
result[resultKey] = (isObject(value) && isObject(origObj[key])) ? changes(value, origObj[key]) : value
}
})
}
return changes(newObj, origObj)
}
This library is not working for me, it returns the whole object using this code const differenc = difference(this.productPreviousCommand, model);
The output of above code is
{
active: true
description: "<p>hello hello 1</p>"
id: "60f8f29dd03dbd2ca3b3dfd1"
title: "hello"
}
Try this function
differenceInObj(firstObj: any, secondObj: any): any {
let differenceObj: any = {};
for (const key in firstObj) {
if (Object.prototype.hasOwnProperty.call(firstObj, key)) {
if(firstObj[key] !== secondObj[key]) {
differenceObj[key] = firstObj[key];
}
}
}
return differenceObj;
}
You can check loop through each key of the first object and compare it with the second object.
function getPropertyDifferences(obj1, obj2) {
return Object.entries(obj1).reduce((diff, [key, value]) => {
// Check if the property exists in obj2.
if (obj2.hasOwnProperty(key)) {
const val = obj2[key];
// Check if obj1's property's value is different from obj2's.
if (val !== value) {
return {
...diff,
[key]: val,
};
}
}
// Otherwise, just return the previous diff object.
return diff;
}, {});
}
const a = {
active: true,
description: '<p>hello</p>',
id: '60f8f29dd03dbd2ca3b3dfd1',
title: 'hello',
};
const b = {
active: true,
description: '<p>hello hello 1</p>',
id: '60f8f29dd03dbd2ca3b3dfd1',
title: 'hello',
};
const c = {
active: true,
description: '<p>hello hello 2</p>',
id: '60f8f29dd03dbd2ca3b3dfd1',
title: 'world',
};
console.log(getPropertyDifferences(a, b));
console.log(getPropertyDifferences(b, c));
function difference(origObj, newObj) {
const origObjKeyList = Object.keys(origObj),
newObjKeyList = Object.keys(newObj);
// if objects length is not same
if (origObjKeyList?.length !== newObjKeyList?.length) {
return;
}
// if object keys some difference in keys
if (Object.keys(origObj).filter((val) => !Object.keys(newObj).includes(val))?.length) {
return;
}
return Object.entries(origObj).reduce(
(acc, [key, value]) => (newObj[key] !== value ? { ...acc, ...{ [key]: newObj[key] } } : acc),
[]
);
}
const a = {
active: true,
description: '<p>hello</p>',
id: '60f8f29dd03dbd2ca3b3dfd1',
title: 'hello',
};
const b = {
active: true,
description: '<p>hello hello 1</p>',
id: '60f8f29dd03dbd2ca3b3dfd1',
title: 'hello',
};
console.log(difference(a, b));
You can try this code.
function difference(origObj, newObj) {
const origObjKeyList = Object.keys(origObj),
newObjKeyList = Object.keys(newObj);
// if objects length is not same
if (origObjKeyList?.length !== newObjKeyList?.length) {
return;
}
// if object keys is not same
if (Object.keys(origObj).filter((val) => !Object.keys(newObj).includes(val))?.length) {
return;
}
return Object.entries(origObj).reduce(
(acc, [key, value]) => (newObj[key] !== value ? { ...acc, ...{ [key]: newObj[key] } } : acc),
[]
);
}