How to modify a nested json position with a trace string - javascript

I am creating a web app in order to do a json builder. The problem is I have the json in javascript and I have a string with the position of the element to change.
For me it's easy to access to it doing for loops, but the goal is update or delete the field or array.
The only success solution I have found, it's an switch with the possibles splited trace array lengths.
Json example:
{
"name" : "Marcelino"
"id" : "${id}"
"poderes":
{
"poder1" : "volar"
"poder2" : "echar fuego"
"poder3" : "${poder4}"
"array":
{
"Elemento1" : "adada"
}
}
}
I want to modify the following key:value pair:
"poderes" : "volar"
I have the trace in a variable:
trace = poderes-poder1
The current solution
...
let traceArray = trace.split("-");
...
switch(traceArray.length){
...
case1:
json[traceArray[0]]
...
case2:
json[traceArray[0]][traceArray[1]]
...
case3:
json[traceArray[0]][traceArray[1]][traceArray[2]]
...
Looking for better solution.
Thanks so much for the help.

You could reduce the path by saving the last key and change either the value or delete this property.
function change(object, path, value) {
var keys = path.split('-'),
last = keys.pop(),
reference = keys.reduce((o, k) => o[k], object);
if (value === DELETE) {
delete reference[last];
} else {
reference[last] = value;
}
}
const DELETE = Symbol('delete this property');
var data = { name: "Marcelino", id: "${id}", poderes: { poder1: "volar", poder2: "echar fuego", poder3: "${poder4}", array: { Elemento1: "adada" } } },
target = 'poderes-poder1';
change(data, target, 'foo')
console.log(data);
change(data, target, DELETE);
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }

I think the best way you could tackle this is by reading the JSON into a Javascript object, mutate it and then convert it back to JSON:
const hero = JSON.parse(yourJsonString);
hero.poderes.poder1 = "invisibility";
const outputJson = JSON.strigify(hero);

Related

How to get specific data in JSON result

Here my JSON result of my "modeles" of car:
[
{
"idModele":1,
"modele":"M3",
"marque":{
"idMarque":1,
"marque":"BMW"
}
},
{
"idModele":2,
"modele":"RS6",
"marque":{
"idMarque":2,
"marque":"Audi"
}
},
{
"idModele":3,
"modele":"C63 AMG",
"marque":{
"idMarque":3,
"marque":"Mercedes"
}
},
{
"idModele":4,
"modele":"Clio RS Trophy",
"marque":{
"idMarque":4,
"marque":"Renault"
}
},
{
"idModele":5,
"modele":"Scirocco Type R",
"marque":{
"idMarque":5,
"marque":"Volkswagen"
}
},
{
"idModele":6,
"modele":"118d",
"marque":{
"idMarque":1,
"marque":"BMW"
}
}
]
I just want to get the "modeles" that have the "idMarque:1" (BMW) (in my result they have 2 "modeles") but I don't know how to do it.
My backend : API REST with SpringBoot
My frontend : Angular
Assuming the json array is stored in the variable result, you may simply:
Loop over the json-array.
Check each json-object for the desired condition.
for (let i = 0; i < result.length; i++) {
if (result[i].marque.idMarque === 1) {
console.log('Found it ', result[i]);
}
}
Even simpler:
result.filter(e => e.marque.idMarque === 1);
First, just for clarification, this is a javascript question. It doesn't matter what your backend or frontend is.
Answering your question, you can filter your result to get only the elements you're seeking:
filteredCars = cars.filter(car => car.marque.idMarque === 1)
This will filter the cars with marque.idMarque = 1.
You can find about the filter function on the docs.
You can get the model having idMarque:1 using filter operator. For example you get the JSON result in result class variable. Then you can use filter as follows.
let BMWCars = this.result.filter(e => e.marque.idMarque == 1);
Is a good idea to check, if you have searched object values, so:
let filtered = models
.filter(item => item.marque && item.marque.idMarque
? item.marque.idMarque === 1
: '')
In this case, if you did not get error, when marque key is missing from server response.

Javascript Key/Value Pairing with Arrays

I am trying to wrap my head around how I might accomplish something like this, structurally:
var keywordDataProducts =
[
{"keyword" : "keyword1", "list" : [ "DP1", "DP2" ] },
{"keyword" : "keyword2", "list" : [ "DP1" ] }
];
But of course, without the values being hard coded. For instance, we currently loop through all the DP values (DP1, DP2, DP3, etc..) - which all have 0-M keywords. I'm trying to create an inverse lookup of that, where you can get all DPs that use a particular keyword. I have code that uses the structure above perfectly, but I just need the data to get populated more dynamically.
Do I initialize the var keywordDataProducts = []; declaration with anything in it, or define the structure of it having a keyword and a list (which is an array)? Or do you leave it as an array with nothing about it, and define that when you're adding items?
I've heard associative arrays can be used for a situation like this, but I'm not quite wrapping my head around that at the moment. I've also seen objects with {} usages, but there is no push there and I need an array of keywords, which also contains arrays of DPs (list). Thoughts?
You would do something like this, but you didn't clearly describe what the input look like and what output you're looking for.
function fn (input) {
var ouput = {};
input.forEach( function (DP) {
for (prop in DP) {
if (DP.hasOwnProperty(prop) {
if (output[prop]) {
output[prop].push(DP);
} else {
output[prop] = [DP];
}
}
}
});
return output;
}
This takes this kind of input
[{"alpha":...}, {"beta":..., "delta":...}, {"alpha":..., "gamma":...}]
and returns
{"alpha":[{"alpha":...}, {"alpha":..., "gamma":...}]}, "beta":{"beta":..., "delta":...}, "delta":{"beta":..., "delta":...}, "gamma":{"alpha":..., "gamma":...}}
I don't know how you want your output so I just made an object with each keyword as its own key for the DP values.
var data = [{dp: "dp1", keys: ["key1", "key2", "key3"]}, {dp: "dp2", keys: ["key1", "key2", "key3"]}, {dp: "dp3", keys: ["key1", "key2", "key3"]},];
function keyWordArray(arr) {
var newObj = {};
arr.forEach((obj) => {
obj.keys.forEach((keyVal) => {
if(newObj.hasOwnProperty(keyVal)){
newObj[keyVal].dp.push(obj.dp);
} else {
newObj[keyVal] = {dp:[obj.dp],};
}
});
});
return newObj;
}
document.getElementById("data").innerHTML = JSON.stringify(keyWordArray(data));
<div id="data">
</div>
You can treat objects as associative arrays, and you don't have to use "push" to add a new element.
// Create your object like this
var keywordDataProducts =
{
"keyword1" : { "list" : [ "DP1", "DP2"] },
"keyword2" : { "list" : [ "DP1" ] }
};
// Treat it like an associative array
var keyword1 = keywordDataProducts["keyword1"];
alert("keyword1 = " + keyword1.list.join(", "));
// Add to it like this
keywordDataProducts["keyword3"] = { "list" : ["DP3", "DP4"] };
// See the new object includes your new keyword
alert(JSON.stringify(keywordDataProducts));
// To iterate the keys of your object, you can do something like this
for(var item in keywordDataProducts)
{
if(keywordDataProducts.hasOwnProperty(item))
{
alert(item);
}
}
You can see the fiddle here;
https://jsfiddle.net/gksjtwr6/2/

How to save distinct values in an object in javascript?

I have a bunch of log data which is stored in a variable. Each log value contains a camera name and system ip. I want to create an object which has names as all the distinct system ip's and corresponding value as an array which contains all the camera names corresponding to that system ip. Below is my code ---
$http(req).success(function(data){
$scope.logs = data;
$scope.cameras={};
var v =$scope.logs[0].systemIp;
$scope.cameras["v"]=[];
$scope.cameras["v"].push($scope.logs[0].cameraName);
for(i=1;i<$scope.logs.length;i++){
v=$scope.logs[i].systemIp;
var flag=0;
for(j in $scope.cameras){
if(j==="v")
{
flag=1;
break;
}
}
if(flag==0)
{
$scope.cameras["j"]=[];
$scope.cameras["j"].push($scope.logs[i].cameraName);
}
else if(flag==1)
{
$scope.cameras["v"].push($scope.logs[i].cameraName);
}
}});
And this is what my data looks like --
[{
"_id": "57683fd82c77bb5a1a49a2aa",
"cameraIp": "192.16.0.9",
"cameraName": "garage2",
"systemIp": "192.168.0.2"
},
{
"_id": "57683f8e2c77bb5a1a49a2a9",
"cameraIp": "192.16.0.8",
"cameraName": "garage1",
"systemIp": "192.168.0.2"
},
{
"_id": "57683f5e2c77bb5a1a49a2a8",
"cameraIp": "192.16.0.7",
"cameraName": "Back Door",
"systemIp": "192.168.0.4"
}]
When I print $scope.cameras on my console it gives this as the output -
Object { v: Array[3] }
I want by cameras object to look like this --
{ "192.168.0.2" : [ "garage1" , "garage2"] ,
"192.168.0.4" : [ "Back Door"] }
I am new to javascript, any help is appreciated.
If you are using the Lodash or Underscore library (which I highly recommend), you can just use the _.groupBy() function to do what you are after (along with some other functions to ensure all values are unique).
However, you can also easily implement it yourself:
function groupByDistinct(arr, prop, mapFn) {
mapFn = mapFn || function (x) { return x; };
var output = {};
arr.forEach(function (item) {
var key = item[prop],
val = mapFn(item);
if (!output[key]) {
output[key] = [val];
return;
}
if (output[key].indexOf(val) < 0) {
output[key].push(val);
}
});
return output;
}
Use it for your code like so:
$scope.cameras = groupByDistinct(data, 'cameraIp', function (logEntry) {
return logEntry.cameraName;
});
You are passing a string such as "v" or "j" as your object key, and this string are actually ending being your object key and not the value of this variables as you want. You can use something like this:
for(i=0; i < $scope.logs.length; i++){
var _sysIp = $scope.logs[i].systemIp,
_camName = $scope.logs[i].cameraName;
if(!$scope.cameras.hasOwnProperty(_sysIp)) {
$scope.cameras[_sysIp] = [_camName];
} else if ($scope.cameras[_sysIp].indexOf(_camName) < 0) {
$scope.cameras[_sysIp].push(_camName);
}
}

Reconstruct JSON after duplicates have been removed

I have the following JSON -
{
"node1":[
{
"one":"foo",
"two":"foo",
"three":"foo",
"four":"foo"
},
{
"one":"bar",
"two":"bar",
"three":"bar",
"four":"bar"
},
{
"one":"foo",
"two":"foo",
"three":"foo",
"four":"foo"
}
],
"node2":[
{
"link":"baz",
"link2":"baz"
},
{
"link":"baz",
"link2":"baz"
},
{
"link":"qux",
"link2":"qux"
},
]
};
I have the following javascript that will remove duplicates from the node1 section -
function groupBy(items, propertyName) {
var result = [];
$.each(items, function (index, item) {
if ($.inArray(item[propertyName], result) == -1) {
result.push(item[propertyName]);
}
});
return result;
}
groupBy(catalog.node1, 'one');
However this does not account for dupicates in node2.
The resulting JSON I require is to look like -
{
"node1":[
{
"one":"foo",
"two":"foo",
"three":"foo",
"four":"foo"
},
{
"one":"bar",
"two":"bar",
"three":"bar",
"four":"bar"
}
],
"node2":[
{
"link":"baz",
"link2":"baz"
},
{
"link":"qux",
"link2":"qux"
},
]
};
However I cannot get this to work and groupBy only returns a string with the duplicates removed not a restructured JSON?
You should probably look for some good implementation of a JavaScript set and use that to represent your node objects. The set data structure would ensure that you only keep unique items.
On the other hand, you may try to write your own dedup algorithm. This is one example
function dedup(data, equals){
if(data.length > 1){
return data.reduce(function(set, item){
var alreadyExist = set.some(function(unique){
return equals(unique, item);
});
if(!alreadyExist){
set.push(item)
}
return set;
},[]);
}
return [].concat(data);
}
Unfortunately, the performance of this algorithm is not too good, I think somewhat like O(n^2/2) since I check the set of unique items every time to verify if a given item exists. This won't be a big deal if your structure is really that small. But at any rate, this is where a hash-based or a tree-based algorithm would probably be better.
You can also see that I have abstracted away the definition of what is "equal". So you can provide that in a secondary function. Most likely the use of JSON.stringify is a bad idea because it takes time to serialize an object. If you can write your own customized algorithm to compare key by key that'd be probably better.
So, a naive (not recommended) implementation of equals could be somewhat like the proposed in the other answer:
var equals = function(left, right){
return JSON.stringify(left) === JSON.stringify(right);
};
And then you could simply do:
var res = Object.keys(source).reduce(function(res, key){
res[key] = dedup(source[key], equals);
return res;
},{});
Here is my version:
var obj = {} // JSON object provided in the post.
var result = Object.keys(obj);
var test = result.map(function(o){
obj[o] = obj[o].reduce(function(a,c){
if (!a.some(function(item){
return JSON.stringify(item) === JSON.stringify(c); })){
a.push(c);
}
return a;
},[]); return obj[o]; });
console.log(obj);//outputs the expected result
Using Array.prototype.reduce along with Array.prototype.some I searched for all the items being added into the new array generated into Array.prototype.reduce in the var named a by doing:
a.some(function(item){ return JSON.stringify(item) === JSON.stringify(c); })
Array.prototype.some will loop trough this new array and compare the existing items against the new item c using JSON.stringify.
Try this:
var duplicatedDataArray = [];
var DuplicatedArray = [];
//Avoiding Duplicate in Array Datas
var givenData = {givenDataForDuplication : givenArray};
$.each(givenData.givenDataForDuplication, function (index, value) {
if ($.inArray(value.ItemName, duplicatedDataArray) == -1) {
duplicatedDataArray.push(value.ItemName);
DuplicatedArray.push(value);
}
});

Look for a value for a given key in JSON and change the value using javascript

I am looking to write a function which can look up a value based on a key and replace that value with another. The key is a tree from the start node of JSON. Here is the example.
var myData = {
name : 'Dan',
address: {
city : 'Santa Clara',
details : {
'prevhouse' : ''
}
}
}
Input to the function is a key tree. For eg, myData-address-details-prevhouse
When I pass this key with a new value, say 'Texas', the prevhouse value will get changed to the new value I am sending.
and new JSON will be
var myData = {
name : 'Dan',
address: {
city : 'Santa Clara',
details : {
'prevhouse' : 'Texas'
}
}
}
Here is what I wrote so far
var tree = key.split("-");
now the tree variable contains ["myData","address", "details","prevhouse"]
I know that we can access the object using myData[tree[0]][tree[1]][tree[2]], but somehow not able to get it dynamic from parsed value.
how do we generate this dynamically since the length of the depth is not known till runtime.
Hope to get a help.
try with this code:
var myData = {
name: 'Dan',
address: {
city: 'Santa Clara',
details: {
prevhouse: ''
}
}
};
function setAttribute(obj, key, value) {
var i = 1,
attrs = key.split('-'),
max = attrs.length - 1;
for (; i < max; i++) {
attr = attrs[i];
obj = obj[attr];
}
obj[attrs[max]] = value;
console.log('myData=', myData);
}
setAttribute(myData, "myData-address-details-prevhouse", "Texas");
here a working jsfiddle demo; see the console for the result
You should be able to iterate through each key because your JSON is just a JS object. So go through each key, check if it's defined, if it is, use that object for your next check. That'll get you where you want to go. Keep in mind you'll be setting the last key to your value.
basic psuedo-code without dealing with setting:
obj = data;
for (key in keys) {
obj = obj[key]
}
Something like this would do:
function update(node, path, value) {
path = path.split('-');
do {
node = node[path.splice(0, 1)];
} while(path.length > 1);
node[path[0]] = value;
}
Given that myData is the object, I think you should be using myData[tree[1]][tree[2]][tree[3]] and throwing away the first item in the array.
Something like this should work recursively (untested)
function updateValue(obj, key, value)
{
var keys = key.split('-');
updateObjectValue(obj, keys.shift(), value);
}
function updateObjectValue(obj, keyArray, value)
{
if (keyArray.length == 1) {
obj[keyArray[0]] = value;
}
else if (keyArray.length > 1) {
updateObject(obj[keyArray[0]], keyArray.shift(), value);
}
}

Categories