Accessing Nested elements in a JSON array - json

How would I access the value label in the following JSON array
[ { _id: 596e0053e405e523bca7d289,
'[{"type":"button","label":"Button","subtype":"button","className":"btn-
default btn","name":"button-1500381266064","style":"de
fault"}]': '' },
{ _id: 596e0053e405e523bca7d28a } ]

As I understand your JSON is name of a property,Given that GUID is provided as string this should work:
var t=[ { _id: '596e0053e405e523bca7d289',
'[{"type":"button","label":"Button","subtype":"button","className":"btn-default btn","name":"button-1500381266064","style":"default"}]': '' },{ _id: '596e0053e405e523bca7d28a' } ]
function propName(prop, value){
for(var i in prop) {
if (prop[i] == value){
return i;
}
}
return false;
}
console.log(JSON.parse(propName(t[0], ""))[0].label)

Related

TypeScript: find values of certain keys in JSON

I have a JSON that contains a lot of data, here's an example of it:
{
"type":"doc",
"content":[
{
"type":"paragraph",
"content":[
{
"text":"this is a simple page, about a simple umbrella.",
"type":"text"
}
]
},
{
"type":"paragraph",
"content":[
{
"text":"you can use this text to find the umbrella page.",
"type":"text"
}
]
},
{
"type":"paragraph",
"content":[
{
"text":"do you like it?",
"type":"text"
}
]
}
}
I want to extract the value of text key, no matter where the key is located. I'm trying to go over the keys using Object.keys but it only returns the top-level keys:
for (let x of Object.keys(someJson)) {
console.log(x);
}
How can I find all the values of text in this JSON, no matter where in the JSON it is?
You can use JSON.stringify trick, you can intercept all keys from it
function find(obj: object, key: string) {
const ret: any[] = [];
JSON.stringify(obj, (_, nested) => {
if (nested && nested[key]) {
ret.push(nested[key]);
}
return nested;
});
return ret;
};
...
const o = {
key: '123',
a: {
key: 'hello',
b: [
{
c: {
key: 123,
},
},
],
},
};
it('123', () => {
console.log(JSON.stringify(find(o, 'key'))); // ["123","hello",123]
});
if you want for generic JSON just call this function and pass your object :
function printText(obj){
if(Array.isArray(obj)){
for(const o of obj){
printText(o);
}
}else if(typeof obj === "object"){
if (obj){
for(const o of Object.keys(obj)){
if(o==="text"){
console.log(obj.text);
}else{
printText(obj[o]);
}
}
}
}
}

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?

JSON transform in typescript

I'm quite newbie in this sort of stuffs. I have much bigger JSON like this:
{ "X": {
"child1": {
"k1": [],
"k2": "12",
"k3": "abc"
},
"ver": {
"dev1": {
"key1": "0x0100"
},
"dev2": {
"key1": "0x0003",
"key2": "0x0300"
},
"dev3": {
"key1": "0x990",
"key3": "0x0400",
"key2": "0x0100"
}}}}
As I would need to use angular tree component I need to transform the format above to something like this:
{name:X, children: [{name: child1, children: [{name: k1, children: [{name: []}]}]....
My question is how to go through the whole json to make this transformation? It should be probably possible via recursion, but I have never tried it.
My try for recursion:
recursive(obj) {
if (obj instanceof String) {
return {name: obj};
} else if (obj instanceof Array) {
const arr = [];
obj.forEach(item => {
arr.push({name: item})
return arr;
});
} else {
Object.keys(item => {
return this.recursive(obj[item]);
});
}
}
You're close, but you need to make sure to return something from each case of the recursive function. Returning a value from a callback will not return it from the main function. Also, Object.keys just returns an array of keys; if you want to iterate over them, you have to do that separately. This would be my proposed solution:
recursive(name, obj) {
if (typeof obj === "string") {
return { name: name + ": " + obj };
} else if (obj instanceof Array) {
return { name: name, children: obj.map(item => this.recursive("", item)) };
} else {
return { name: name, children: Object.keys(obj).map(k => this.recursive(k, obj[k])) };
}
}
You can adjust the way the names are handled as desired.

How to form a new object from a json as key value pair in Typescript?

I have a below json array of objects which have data of currency list.
[
{
id:"AUD",
value:"1.55"
},
{
id:"BGN",
value:"1.95"
},
{
id:"USD",
value:"1.17"
},
{
id:"CAD",
value:"1.51"
},
{
id:"EUR",
value:"1"
},
{
id:"INR",
value:"80.00"
}
]
I want to form a new array of object say newList with only currency value for USD, CAD and EUR. I can manually find the position of the object(eg: say item[3].value will give rate for CAD)and update the new object but I want to look for key values and get the values instead of getting index positions manually. How to do the same?
I hope this is what you expect.
This is your original list.
const list = [{ id: "AUD", value: "1.55" }, { id: "BGN", value: "1.95" }, { id: "USD", value: "1.17" }, { id: "CAD", value: "1.51" }, { id: "EUR", value: "1" }, { id: "INR", value: "80.00" }];
And this is how you can extract the wanted objects by comparison with their id.
const newList = list.filter(el => this.matches(el.id));
console.log(newList);
This method does the comparison for you and returns true when id matches. You can dynamically remove or add currencies.
private matches(id: string): boolean {
let match: boolean = false;
switch (id) {
case 'AUD':
match = true;
break;
case 'USD':
match = true;
break;
case 'EUR':
match = true;
break;
default:
match = false;
break;
}
return match;
}