Basically I have got an object, which will be multi-dimensional and the properties could be named anything and it could have many dimensions.
At some point I will need to append/splice a property within this object, from code which won't know it's position.
So, an example object:
let obj = {
response: {
locations: {
data: [
0: Object,
1: Object,
2: Object,
]
}
},
endpoint: null
}
I need to splice out data.locations.data[1], the only information I have is the below array and the index. Obviously I will know the first property will be response.
['locations','data']
index: 1
Edit:
My mistake, the data property has an array value not an object!
You can use Array#reduce() and pass in obj.response as the start value to get at the nested parent which based on the array shown would be obj.response.locations.data.
Then splice() the indexed item in that parent or do whatever other modifications are needed
const arr = ['locations','data'],
index= 1,
obj = {
response: {
locations: {
data: [{id:1},{id:2}, {id:3}]
}
},
endpoint: null
}
const targetArr = arr.reduce((a,c)=> (a[c]), obj.response);
targetArr.splice(index,1);
console.log(obj)
Related
This question already has answers here:
Find object by id in an array of JavaScript objects
(36 answers)
Closed 2 years ago.
I have a file with 1000s of json rows like below. Im having difficulties locating a specific key in the array.
example json:
{"connection":"98374"
,"db":"8",
,"timestamp":"159905411631"
,"event":"DataCatch"
,"data":[{"key":"ruleid","value":"111"}
,{"key":"responseid","value":"155-response-4"}
,{"key":"responsetype","value":"Capture"}
,{"key":"reason","value":"ClientVisit"}
,{"key":"subreason","value":""}
,{"key":"score","value":"0.00"}
,{"key":"comment","value":""}]
}
I need to be able to find the "reason" key in the "data" array and replace the "value" with "test". The "data" array doesn't always appear on every json row, only when the "event" "dataCatch" is present.
I can parse it into a variable but I can only call the "data" array as a whole. Any ideas how to target specific values in an array?
Having a little trouble with this in Typescript.
There are any number of ways to go about this, but here's one.
First, parse your JSON into an array of objects.
Each element of the array will then look something like this:
{
connection: '98374',
db: '8',
timestamp: '159905411631'
event: 'DataCatch',
data: [
{ key: 'ruleid', value: '111' },
{ key: 'responseid', value: '155-response-4' },
{ key: 'responsetype', value: 'Capture' },
{ key: 'reason', value: 'ClientVisit' },
{ key: 'subreason', value: '' },
{ key: 'score', value: '0.00' },
{ key: 'comment', value: '' },
],
}
Let's call our array of objects allData, so we can refer to it later.
Now we can begin our "surgery".
We'll work from the inside-out, first looking at what needs to be done to a specific entry in an element's data array.
Here's a function that will do just what we need:
function updateReason(entry) {
if (entry.key === 'reason') {
return { ...entry, value: 'test' };
} else {
return entry;
}
}
This function checks if the provided entry has a key with a value of 'reason', and -- if so -- returns a new entry that is identical to the provided one except its value is 'test'.
How can we use this to update an entire data array (in an entry that has data, that is)?
We simply delegate the work to our dear friend map:
function updateData(data) {
// or simply `data.map(updateEntry);`
return data.map(entry => updateEntry(entry));
}
We're slowly working our way "outwards".
What about updating an entire entry in our big allData array (which may or may not contain data)?
// I've called such an entry a "collection", because I already used the name
// "entry" above :(
// A "collection" is just an entry in the big `allData` array.
function updateCollection(collection) {
if (collection.event === 'DataCatch') {
return {
...collection, // Leave everything else the way it is
data: updateData(collection.data), // But update the `data` array
};
} else {
return collection;
}
}
So close.
The last thing we need to do is apply this transformation to every element of our parsed allData array:
// or `allData.map(updateCollection);`
const updatedData = allData.map(collection => updateCollection(collection));
Also:
Q: Wouldn't it be cheaper to mutate the entry?
A: It would be cheaper, but not that much cheaper, due to a large amount of "structural sharing" that occurs here. I would recommend this approach unless you either need to mutate your input for some reason, or performance requirements demand it.
You need to map over the data key in your data variable like this.
data.data = data.data.map((item) => {
if (item.key === "reason") {
item.value = "test";
}
return item;
});
the data key is an array of values, so you need to loop through it and compare the value of the key property to the value you are looking for, if it matches then you can update the value property
https://codesandbox.io/s/angry-shirley-1gh83?file=/src/index.ts:666-782
I have a simple scenario where I am trying to update an array value that is part of an object, but the object does not seem to reflect the update.
Code:
var request =
{
description: 'my-desc',
details: []
};
request.details['shelf-info'] =
[
{
key: 'ShelfNumber',
value: '100'
}
];
console.log(JSON.stringify(request))
With the assignment of shelf-info, I would have expected the resulting output to be similar to:
Desired Output:
{ "description": "my-desc", "details": { "shelf-info": [ "key": "ShelfNumber", "value": "100" ] } }
but the update doesn't seem to have taken effect:
Actual Output:
{"description":"my-desc","details":[]}
I have found that I can add simple objects (strings) to an array using append, but shelf-info may or may not already be in the request.details section by the time this code gets executed...how would I handle both cases?
You want a plain object ({}) for details, not an array ([]).
When arrays are serialized to JSON, the JSON output only includes values that are stored in whole-number indices. Arrays may validly have other properties whose key names are not non-negative integers (such as the string shelf-info) but those properties are not included the JSON serialization of the array.
You're using an array as if it's an object, which it technically is, but that won't add anything to the array, and it won't convert the array to a regular object with key/value pairs.
Easy fix:
var request = {
description: 'my-desc',
details: { }
};
Also since it's 2020 you should be using let instead of var in most cases.
Try Below. Detail property should be an object.
var request =
{
description: 'my-desc',
details: {}
};
request.details['shelf-info'] =
[
{
key: 'ShelfNumber',
value: '100'
}
];
console.log(JSON.stringify(request))
I want to set multiple objects as multiple values of another object. So for example
let dataObj ={}
const personData = {name:"sai",age:"20"}
const ids = {id1:"1231455",id2:"425325232"}
dataObj.personData = personData;
dataObj.ids = ids
console.log(dataObj);
'personData' is a object and 'ids' is a object.Im setting these 2 objects as 2 values for 'dataObj'.
I was wondering is there a shorter way to achieve this like:
let dataObj ={}
const personData = {name:"sai",age:"20"}
const ids = {id1:"1231455",id2:"425325232"}
dataObj = personData;
dataObj = ids
console.log(dataObj);
The problem with the alternative I suggested is that it wont set 'key' of 'dataObj' object.It will just set the values of 'personData' and 'ids' to the value of dataObj.Is there any way I can achieve this ? Specifying multiple objects as values to another object with keys?
You can achieve this using the spread syntax:
let dataObj = {};
const personData = {name:"sai",age:"20"}
const ids = {id1:"1231455",id2:"425325232"}
dataObj = { ...dataObj, personData, ids };
console.log(dataObj);
/*
output :
value of dataObj:
{
personData: {
name: "sai",
age" "20"
},
ids: {
id1: "1231455",
id2: "425325232"
}
}
*/
I'll try and explain spread using the above example. First we start with an empty object dataObj: {}. We want to add new properties to that object: personData with the personData object as value and ids with the ids object as value.
ES2015 added a shorthand syntax for setting property definitions in objects. That's what been used here:
dataObj = { personData, ids };
This is simply a cleaner way of writing
dataObj = {
personData: personData,
ids: ids
};
More info on this can be found on MDN.
Because you want to initialise your object before, we can't simply overwrite the object, but we need to add the new properties to the existing object. This can be done using the spread syntax.
const oldObject = { key: 'value', anotherKey: 'another value' };
let newObject = { ...oldObject };
// newObject value: { key: 'value', anotherKey: 'another value' };
The oldObject was 'spreaded' in newObject. Resulting it in having the same key-value pairs as oldObject.
In your code example we assign a new object to dataObj. In that new object we spread all properties which are in the current dataObj: { ...dataObj and then add the new properties: , personData, ids }.
I hope this explanation is clear, feel free to ask for more info. The spread syntax is very powerful and can be used for a lot of things. So be sure to read up on that.
You can merge two objects as below. You can use '...' spread object. the spread object works for objects as well. Clone an object as shown in below code. for more information please visit https://flaviocopes.com/javascript-spread-operator/
let dataObj = {}
const personData = { name: "sai", age: "20" }
const ids = { id1: "1231455", id2: "425325232" }
dataObj = { ...dataObj, personData, ids }
console.log(dataObj);
Using Javascript, how do I create an array within an object that's within an object, so that my value is stored at: main[1].type[1][0]
I have tried and my code which does not work is as follows:
let main = []
main[1] = {type: {1:['Value1', 'Value2']}, {2:['Value3', 'Value4']}};
console.log(main[1].type[0][1]);
I expect main[1].type[1][0] to be 'Value1' but it is undefined
You're not getting undefined. You have a syntax error. A comma should either be separating array values, or separating object entries. You have a comma here, in an object, so it is expected to have a key after it, not a {
main[1] = {type: {1:['Value1', 'Value2']}, {2:['Value3', 'Value4']}};
|
|
Remove the } and { around this comma
Remove the } and { around the comma so that {1:['Value1', 'Value2'], 2:['Value3', 'Value4']} becomes a single object with two keys:
const main = [];
main[1] = {type: {1:['Value1', 'Value2'], 2:['Value3', 'Value4']}};
console.log( main[1].type[1][0] );
First your declaration is wrong and will not works.
{type: {}, {}} isn't a valid JSON and you must wrap it into [] to create array of object {type: [{}, {}]}.
Also by adding a level you will have to ask for: main[1].type[0][1][0] to get the complet path to Value1
let main = []
main[1] = {type: [{1:['Value1', 'Value2']}, {2:['Value3', 'Value4']}]};
console.log(main[1].type[0][1][0])
Your problem is you can not create an object with a numbered object inside it you have to use the array notation var variableName = [/*variable values here separated by commas*/]
This will fix your problem:
let main = []
main[1] = {
type: [
['Value1', 'Value2'],
['Value3', 'Value4']
]
};
console.log(main[1].type[0][1]);
Breaking down your issue, an object must be "zero or more pairs of property names and associated values of an object." The second value in the question's code does not have a key, causing an uncaught SyntaxError.
Here's an object literal that returns your desired result:
const main = {
1: {
type: { 1: ['Value1', 'Value2'] },
otherType: { 2: ['Value3', 'Value4'] },
},
};
main[1].type[1][0]
=> "Value1"
Object initializer docs
Another option could be to use sparse arrays :
let main = [, { type: [, ['Value1', 'Value2'], ['Value3', 'Value4'] ] } ];
console.log(main[1].type[1][0]);
So I have this code in vue:
export default {
name: 'Test',
data() {
return {
test1: ['1', '2', '3'],
test2: [{
name: 'Hello'
}, {
name: 'Number two'
}, {
name: 'What ever'
}],
};
},
created() {
const first = [...this.test1];
first.forEach((elm, index) => first[index] = 'New');
console.log('first: ', first);
console.log('test1 in data', this.test1);
const second = [...this.test2];
second.forEach(elm => elm.name = 'New');
console.log('second: ', second);
console.log('test2 in data', this.test2);
},
}
After setting the value of each item of the array 'first' (that should be a copy without reference to the data 'test1' array) each item is equal to 'new'. The value of this.test1 doesn't change.
I did the same with test2. Copied and changed the value of each item to 'New'. But now the value of the data array 'test2' also has 'New' in every item.
I have no clue why this is like that. Any ideas?
Spread syntax creates a shallow copy. If your array has primitive types like numbers or strings, it won't update the original array. That's the case with test1. In the second case, only a new array is created. If you push or pop from the array, original array won't be updated. But, the objects are still pointing to their same place in memory. Updating them will update original array's objects as well.
You can use the spread syntax on the individual object to create a copy of the objects:
const second = this.test2.map(o => ({...o}))
You can also use JSON.parse and JSON.stringify. But, if the objects have any function properties, they'll be removed.
const second = JSON.parse(JSON.stringify(this.test2))
The reason it is like that is because you are having an array of Vue data values. So even though you are cloning the Array, you are also copying over each values 'getters' and 'setters' which have a reference to the original array. In order to remove the getters and setters you should do what d-h-e has suggested.
You could also do this.
const second = this.test2.map(() => { name: 'New' } );
console.log('second: ', second);
console.log('test2 in data', this.test2);
Try it with:
const second = JSON.parse(JSON.stringify(this.test2));
The copy method with spreadoperator or Array.from works only with simple arrays.
For deep copy use the method with JSON.parse and JSON.stringify.