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.
Related
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]);
}
}
}
}
}
I have an JSON object that I am trying to map. SO basically the JSON is like this:
{
"Status": true,
"discounts": {
"broker": {
"discount": "1"
},
"dealer": {
"discount": "0.7"
},
"individual": {
"number_of_cars_discount": {
"1": "1",
"10": "1",
"2": "0.98",
"3": "1",
"4": "1",
}
}
}
}
So I set the post and fetch the data.
const [posts, setPosts] = useState({});
useEffect(() => {
const fetchPosts = async () => {
try {
setLoading(true);
const res = await Axios({
});
if (res.status == 200) {
setPosts(res.data);
}
setLoading(false);
} catch (err) {
setError(err.message);
setLoading(false);
}
};
fetchPosts();
}, []);
So to get the value and display it inside the table here is my code:
<tbody>
<td>
{Object.keys(posts).map((post, index) => (
<tr>
<div key={`broker-${index}`}>{post.discounts}</div>
</tr>
))}
</td>
</tbody>
But unfortunately, I am getting nothing.
Thanks for your helps...
Initialize posts with empty array not boolean value:
const [posts, setPosts] = useState([]);
And you have to map on posts directly. So, you don't need to use Object.keys().
You can keep posts as an empty Object when you do useState().
The nested JSON object that you have doesn't work with those cycling you are trying.
If you console.log the key in your arrow function inside the map you would discover that it would be changing value between "Status" and "discounts", so with those keys you cannot access the object inside posts.discounts.broker because those properties don't exist.
posts.discounts.broker.Status and posts.discounts.broker.discounts will always return undefined.
I think you should consider whether you should flatten your nested JSON or, if you just need what's inside discounts.broker, then you can set just that Object inside of posts.
I have a object like this.
sliderArray:
[
"../assets/slides/1.jpg",
"../assets/slides/2.jpg",
]
Can I reformat it like this in Vue?
sliderArray2:
[
{url: require("../assets/slides/1.jpg")},
{url: require("../assets/slides/2.jpg")},
]
This is easy to do with a map, which applies the same function to every element of an array
let obj = { sliderArray: [
"../assets/slides/1.jpg",
"../assets/slides/2.jpg",
]
};
function formatArray(a) {
return a.map(x => { return { url: require(x) } });
}
obj.sliderArray = formatArray(obj.sliderArray);
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
}
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)