Add Properties after json load - json

I have this json:
{
"info": [
{
"id": 999,
"products": [
{
"id": 1,
},
{
"id": 2,
}
]
}
]
}
Info
-- products
-----id
And my factory:
AppAngular.factory('model', ['$http', function ($http) {
return {
load: function (scope) {
$http.get('mydomain/api').success(function (data) {
var myObject = {};
angular.extend(myObject,data);
for (var i = 0; i < myObject.info.length; i++) {
for (var j = 0; j < myObject.info[i].products.length; j++) {
myObject.info[i].products[j].selected = true;
myObject.info[i].products[j].quantity = 1;
.....
}
}
}
});
}
};
} ]);
Theres is a way do add some property after angular.extend, without using a lot of for? We need do add some properties or behavior to the object after make json get.
For exemple:
Info
-- products
-----id
-----selected
-----quantity

You could use angular.forEach:
AppAngular.factory('model', ['$http', function ($http) {
return {
load: function (scope) {
$http.get('mydomain/api').success(function (data) {
var myObject = {};
angular.extend(myObject,data);
angular.forEach(myObject.info, function (info) {
angular.forEach(info.products, function (product) {
product.selected = true;
product.quantity = 1;
.....
});
});
});
}
};
}]);

Related

Printing Ajax results in HTML

I have this J Query code:
$(document).ready(function(){
var $outData = $('#data');
var ajaxUrl = 'url.json';
$.ajax(
{
type: 'GET',
url:ajaxUrl,
success: function (result) {
console.log(result.passwords);
}
})
}
);
JSON file looks like this:
{
"passwords":[
{
"value":"tom",
"count":"432517"
},
{
"value":"anaconda",
"count":"454658"
},
{
"value":"111111",
"count":"148079"
},
What I need to do, is to print out each of these objects to be printed out in an ordered list (for instance it should look like this:
tom 432517
anaconda 454658
111111 148079
So far, nothing I have tried works. Althoug, I can console.log the entire object. Any suggestions?
Example rendering:
var $outData = $('#data');
var ajaxUrl = 'url.json';
$.ajax(
{
type: 'GET',
url:ajaxUrl,
success: function (result) {
result.passwords.forEach(pwd => $outData.append(`<div>${pwd.value} ${pwd.count}</div>`));
}
})
}
);
you can create elements and append to dom when you are done,
const data = {
"passwords": [{
"value": "tom",
"count": "432517"
},
{
"value": "anaconda",
"count": "454658"
},
{
"value": "111111",
"count": "148079"
}
]
}
const ol = document.createElement("ol");
for (const {
value,
count
} of data.passwords) {
const li = document.createElement("li")
li.innerText = `${value} -> ${count}`
ol.appendChild(li)
}
document.querySelector("#root").appendChild(ol)
<div id="root"></div>

ExpressJS set the Depth of JSON Parsing

I want to set the depth of JSON parsing in Express middleware express.json().
For example, if I would set the option to parse the depth=1, then
'{ "email": { "$ne": "user#example.com" } }'
will be parsed to
{ email: "[object Object]" }
-- or --
When I set depth=2, then
'{ "email": { "$ne": "user#example.com" } }'
will be parsed to
{ email: { '$ne': 'user#example.com' } }
And so on,
In this case, there will be no issue of default depth, as the developer will be aware of how many nesting they will allow while development.
PS: It will prevent the application from being vulnerable to NoSQL Injection.
Just write you own middleware:
const get_depth = (obj) => {
let depth = 0
for(const key in obj) {
if( obj[key] instanceof Object ) {
depth = Math.max(get_depth(obj[key]), depth)
}
}
return depth+1
}
const depth_limit = 2
const limit_depth = function(req, res, next) {
if( get_depth(req.body) > depth_limit ) throw new Error("Possible NoSQL Injection")
next()
}
app.use(limit_depth)
Or, if you prefer "[object Object]":
let limit_depth = (obj, current_depth, limit) => {
for(const key in obj) {
if( obj[key] instanceof Object ) {
if( current_depth+1 === limit ) {
obj[key] = "[object Object]" // or something similar
}
else limit_depth(obj[key], current_depth+1, limit)
}
}
}
app.use(function(req, res, next) { limit_depth(req.body, 0, depth_limit); next() })
I write down the query, Maximum 6-8 depth goes. when use lookup inside the lookup.
const [result] = await Collection.aggregate([
{ $match:statusObj },
{
$project:{
_id:1,
name:1
}
},
{
$lookup:{
from:"articles",
let: { "cat_id":"$_id"},
pipeline:[
{
$match:{
$expr:{
$and: [
{ $eq: ["$category_id", "$$cat_id"] },
{ $eq: ["$isDeleted", false] },
{ $eq: ["$type", type] }
]
}
}
},
{
$lookup:{
from:"view_articles",
let: { "article_id":"$_id"},
pipeline:[
{
$match:{
$expr:{
$and: [
{ $eq: ["$article_id", "$$article_id"] },
{ $eq: ["$isDeleted", false] }
]
}
}
}
],
as:"viewCount"
}
},
{
$addFields:{
noOfViewCount : { $size:"$viewCount"}
}
} ],
as:"articleCategoryData"
}
},
{
$addFields: {
postCount: {$size:"$articleCategoryData" },
tempsArray: { $map:
{
input: "$articleCategoryData",
as: "tempData",
in: { $add: "$$tempData.noOfViewCount" }
}
},
},
},
{
$addFields: {
viewCount:{ $sum:"$tempsArray" }
},
},
{
$project:{
_id: 1,
name: 1,
postCount: 1,
viewCount: 1
}
},
{
$facet: {
count: [
{
$count: "total"
}
],
result: [{ $match: {} }, { $skip: skipRecord }, { $limit: limit }]
}
}
]);
you can set depth to 10. If you feel JSON is coming wrong then increase it :)
In case anyone who doesn't want to change the value of req.body, can use this function from here
function serializer(payload: any, cdepth: number, options: Options): void {
const main: any = {}
const maxDepth = typeof options.maxNestingLevel == 'number' ? (options.maxNestingLevel == 0 ? 1 : options.maxNestingLevel) : 1
for (const key in payload) {
// check for object
if (payload[key] instanceof Object) {
// check if depth is limited, replace if needed
if (cdepth === maxDepth) {
main[key] = options.replaceWith
} else {
// serialize the nested
main[key] = serializer(payload[key], cdepth + 1, options)
}
} else {
// add to main object if not to be checked
main[key] = payload[key]
}
}
return main
}

JSON variable block

I am having json template for elasticsearch query:
var getTemplate = function (agg, filter_term) {
var template = {
"size": 0,
track_total_hits: true,
query: {
bool: {
must: [
{
"query_string": {
"query": filter_term
}
},
aggs: {
"nested" : { "value_count" : { "field" : agg } },
agg: {
terms: {
field: agg,
size: 10,
order: {
"_count": "desc"
}
}
}
}
};
return template;
Sometimes, I want to skip the block with query_string so I want to pass in in the function call. So instead of this:
const callTerminated = agg_filter.getTemplate( 'bbbbb', 'aaa');
Do that:
const callTerminated = agg_filter.getTemplate( 'bbbbb', {"query_string": {"query": aaa }});
Or:
const callTerminated = agg_filter.getTemplate( 'bbbbb', "");
But how to change the template query? It wants comma after variable but when I skip query_string, I don't need comma.
New json template:
var getTemplate = function (agg, filter_term) {
var template = {
"size": 0,
track_total_hits: true,
query: {
bool: {
must: [
filter_term //here it wants comma
aggs: {
"nested" : { "value_count" : { "field" : agg } },
agg: {
terms: {
field: agg,
size: 10,
order: {
"_count": "desc"
}
}
}
}
};
return template;
So how to do it?

ajax call and $.watch in Angular

I need to generate a select menu when a button is clicked. I am making an ajax call to get json data from external file, upon button click. which In turn should update the select with data from json. with the code below the select gets updated only after the button is clicked twice. I am watching the jsonData but its not working as expected.
HTML:
<div ng-controller="MainViewCtrl">
<button ng-click="getDeployedResources()"> Load Resources </button>
<select ng-model="selectedOption.name" ng-options="item.name as item.name for item in jsonData"></select>
</div>
json from dropdown.json:
{
"DeployedResources": {
"-env": "dev13",
"ResourceList": {
"-exportTime": 1444999007878,
"Resource": [{
"name": "default",
"type": "project"
},
{
"name": "System",
"type": "project"
},
{
"name": "StratusCommonServices",
"type": "project"
}]
}
}
}
JS:
var app = angular.module('JSONedit', ['ui.sortable'])
.controller('MainViewCtrl', ['$scope', '$http', '$filter','$compile', function ($scope, $http, $filter, $compile) {
$scope.jsonData = {};
$scope.getDeployedResources = function () {
$.ajax({
url: 'json/dropdown.json',
dataType: 'json'
}).done(function (data) {
$scope.jsonData = data.DeployedResources.ResourceList.Resource;
$scope.selectedOption = angular.copy($scope.jsonData[0]);
});
}
$scope.$watch('jsonData', function (json) {
$scope.jsonString = $filter('json')(json);
}, true);
$scope.$watch('jsonString', function (json) {
try {
$scope.jsonData = JSON.parse(json);
$scope.wellFormed = true;
} catch (e) {
$scope.wellFormed = false;
}
}, true);
}])
This is the correct life-cycle of a simple AngularJS Component!
Don't use jQuery for doing something that angular does better!
angular
.module('test', [])
.service('DataService', function($q, $http) {
var self = this;
var mock = {
id: 1,
"DeployedResources": {
"-env": "dev13",
"ResourceList": {
"-exportTime": 1444999007878,
"Resource": [{
"name": "default",
"type": "project"
}, {
"name": "System",
"type": "project"
}, {
"name": "StratusCommonServices",
"type": "project"
}]
}
}
};
self.load = function() {
console.log('loading data', mock.id);
for (var i = 0, len = mock.DeployedResources.ResourceList.Resource.length; i < len; i++) {
mock.DeployedResources.ResourceList.Resource[i].name += mock.id;
}
mock.id += 1;
return $q.when(mock);
return $http
.get('/api/data/')
.then(function(result) {
return result.data;
});
}
})
.controller('TestCtrl', function($scope, DataService) {
var vm = $scope;
vm.select = {
current: null,
items: []
};
vm.loadData = function(event) {
console.count('load data');
return DataService
.load()
.then(function(data) {
vm.current = data.id;
return data.DeployedResources.ResourceList.Resource;
})
.then(function(items) {
vm.select.items = items;
vm.select.current = vm.select.items[0];
})
};
vm.loadData();
});
.select-wrapper {
padding: 1em 2em;
background: yellow;
}
.select-wrapper select {
width: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
<article ng-app="test">
<div ng-controller="TestCtrl">
<button type="button" ng-click="loadData($event);">LoadNew</button>
<div class="select-wrapper">
<select ng-model="select.current" ng-options="item as item.name for item in select.items"></select>
</div>
<div ng-bind="select.items | json"></div>
</div>
</article>

Read in csv data for multiBarHorizontalChart in NVD3?

I'd like to visualise data in a "multiBarHorizontalChart" in NVD3 and read the data from a .csv file.
I'm struggling to get the data in the right format. According to NVD3.org the format for multiBarHorizontalChart has to be:
[
{
"key": "Series 1",
"color": "#d67777",
"values": [
{
"label" : "Group A" ,
"value" : -1.8746444827653
} ,
{
"label" : "Group B" ,
"value" : -8.0961543492239
}
]
},
The code that I'm using is below. Could someone tell me what I'm doing wrong?
d3.csv("File.csv", function (error, csv) {
if (error) return console.log("there was an error loading the csv: " + error);
console.log("there are " + csv.length + " elements in my csv set");
var mmm = ["pre_ineq","post_ineq"];
for (var i = 0; i < mmm.length; i++) {
myall[i].values.label = csv.map(function(d) { return [ d["label"] ]; });
myall[i].values.value = csv.map(function(d) { return [ +d[mmm[i]] ]; });
//or? myall[i].values = csv.map(function(d) { return [ label=d["label"], +d[mmm[i]] ]; });
};
var chart;
nv.addGraph(function() {
var chart = nv.models.multiBarHorizontalChart()
.x(function(d) { return d.label })
.y(function(d) { return d.value })
.margin({top: 30, right: 20, bottom: 50, left: 175})
.showValues(true)
.tooltips(false)
.showControls(false);
chart.yAxis
.tickFormat(d3.format(',.2f'));
d3.select('#chart1')
.datum(myall)
.transition().duration(500)
.call(chart);
nv.utils.windowResize(chart.update);
return chart;
});
});
Thanks a lot!
Guess you should do something like
for (var i = 0; i < mmm.length; i++) {
myall[i].values = csv.map(function(d) {
return { "label": d["label"], "value": +d[mmm[i]] };
});
};
But it's not tested.