Sorting after displaying deep JSON object - javascript

I have a dynamic JSON object that has multi-level depth to support a folder structure.
The object is being stored in a state, looking similar to this:
{
"_contents": [
{
"name": "filename_1",
"path": "filename_1"
},
{
"name": "filename_2",
"path": "filename_2"
}
],
"folder_1": {
"_contents": [
{
"name": "filename_1",
"path": "folder_1/filename_1"
},
{
"name": "filename sdafasdfasdfs",
"path": "sasfasdfas"
}
]
},
"folder_2": {
"_contents": [],
"folder_2_1": {
"_contents": [
{
"name": "filename1.md",
"path": "folder_2/folder_2_1/filename1.md"
}
],
"folder_2_1_1": {
"_contents": [
{
"name": "filename1.md",
"path": "folder_2/folder_2_1/folder_2_1_1/filename1.md"
}
]
}
}
}
}
I then pass my object into a react component that generate a UI folder view.
Using this module : https://www.npmjs.com/package/react-nested-file-tree
The issue I'm running into is that after I pass my object state into the node component, the order of the files are being lost.
They go in 1, 2, 3 and come out in the UI as 2,3,1 (or some other random order).
This seems to be a problem in general with mapping through deep JSON objects. But I haven't found a way to prevent or change this?
Is there any way I can preserve the order of my JSON object, or sort after the UI has been built? I've looked into other modules that generate UI's, and I'm getting similar results.
EDIT: I should note that I'm restricted to building my JSON object to fit into the format of whatever module I'm using.

Related

React. Streaming JSON file

I don't have any backend logic and database. For data I just use a json file of humans.
Here it is:
[
{
"id": 0,
"name": "Andrew"
},
{
"id": 1,
"name": "Daniel"
},
{
"id": 2,
"name": "John"
},
{
"id": 3,
"name": "Frank"
}
]
Can I somehow stream this JSON file in React (i.e. on client side) to, for example, retrieve only the first two notes and return the array? I tried FS module but it only works for SSR. Or there's no way I can runtime stream it getting desired data? I just don't wanna return the whole array since I'm trying to imitate a backend database

JSON : Accessing specific leaf, in variable depth branches

So, I have a JSON object built like this (see below), for which I'm trying to access the "layers" leaf that is not of "layerSection" type. I know I could use something like myJsonObject.layers[0].layers[0].layers[0].layers[0].name, but the thing is, I never know how "deep" the leaf is gonna be in its branch. Sometimes, there's no "layerSection" layers at all, but sometimes, there could be a dozen. (or more... there's actually no limit to the number of "layerSection")
To make things even worst, there are also some "empty" branches, with a few "layerSection" layers, without any "normal" layers at the end of it. Those need to be ignored.
And finally, once I get to the leaf, I need to know how deep it's actually is. In other words, I need to know how many "layerSection" I had to go through to get to the leaf.
I'm not used to deal with more complex JSON objects like this. Any help would be really apreciated.
Thanks a million !
Here's the json object :
{
"version": "1.6.1",
"timeStamp": 1592062633.423,
"layers": [
{
"id": 13,
"index": 10,
"type": "layerSection",
"name": "Group 1",
"layers": [
{
"id": 15,
"index": 9,
"type": "layerSection",
"name": "Group 2",
"layers": [
{
"id": 17,
"index": 8,
"type": "layerSection",
"name": "Group 3",
"layers": [
{
"id": 12,
"index": 7,
"type": "adjustmentLayer",
"name": "The leaf I am trying to get to",
"visible": true,
"clipped": true,
"adjustment": {
"presetKind": "presetKindDefault",
"class": "curves"
}
}
]
}
]
}
]
}
]
}
You can think of this JSON structure as a tree data structure. There are some ways to get the leaf nodes of a tree, here I suggest using Depth-First Search to get the leaf layer names.
Suppose you define a leaf layer is a layer which has no more children layers, that's when you return the name of the layer. This function returns all the leaf layer names in your JSON structure along with how deep they are in the JSON.
function getLeafLayerNames(data, depth = 0) {
if (!data.layers) return [{ name: data.name, depth }]
const names = []
for (const layer of data.layers) {
const n = getLeafLayerNames(layer, depth + 1) // DFS recursive, depth increases by 1
names.push(...n)
}
return names.filter(n => n)
}
At last, I use a filter to select only defined layer names. An undefined value can be found when a leaf layer has no property name in it.

Ember unknown relationship

I'm currently building software with Rails + Ember 3.12, but hitting a strange issue.
My models are the following:
// test-case-run
import DS from 'ember-data';
const { Model } = DS;
export default Model.extend({
testCase: DS.belongsTo('test-case'),
testCaseRunLogs: DS.hasMany('test-case-run-logs')
});
// test-case-run-log
import DS from 'ember-data';
const { Model } = DS;
export default Model.extend({
testCaseRun: DS.belongsTo('test-case-run'),
payload: DS.attr('')
});
And, my backend is returning the following payload:
{
"data": {
"id": "83",
"type": "test_case_run",
"relationships": {
"test_case": {
"data": {
"id": "90",
"type": "test_case"
}
},
"test_case_run_logs": {
"data": []
}
}
}
}
{
"data": {
"id": "83",
"type": "test_case_run",
"relationships": {
"test_case": {
"data": {
"id": "90",
"type": "test_case"
}
},
"test_case_run_logs": {
"data": [
{
"id": "426",
"type": "test_case_run_log"
}
]
}
}
},
"included": [
{
"id": "426",
"type": "test_case_run_log",
"attributes": {
"payload": "SCREENSHOT"
},
"relationships": {
"test_case_run": {
"data": {
"id": "83",
"type": "test_case_run"
}
}
}
}
]
}
I've got a custom adapter defining:
pathForType(type) {
return underscore(pluralize(type));
}
So, I think that everything should go well.
However, when I get into the ember inspector, I've got the following:
It seems that my relationship is not loaded properly.
And, I cannot access any data, such as:
log.get('testCaseRun') // that is null
run.get('testCaseRunLogs.length') // it returns 0
This is quite strange, as my records are loaded in the store, but not their relationships.
I have no idea on how to troubleshoot this, since the amount of information I can get from ember is quite limited (there is no error, the format looks good, ...).
Could someone help me to understand what's wrong with my calls? I've tried many things, such as renaming my models, but this does not improve the situation.
Moreover, this model is the only one, which I have problem with. All my other models don't have this problem. So, that's a bit weird.
Thanks a lot
The unknown in <(unknown):ember264> refers to the name of the class. That doesn't mean that your relationship is not loaded correctly. It's just Ember Data using anonymous classes.
To see the data of the relationship you could click on that string and afterwards on content. Another option is passing the full record to the console using the $E link in top right corner. Afterwards you could interact with the record on console, e.g. do a $E.get('testCaseRun.id').
By the way: You don't need to explicitly declare the model name on relationship definition if it's matches the dasherized property name. So testCaseRun: DS.belongsTo('test-case-run') is the same as testCaseRun: DS.belongsTo().
Try to declare hasMany relationship with the model name without 's'
testCaseRunLogs: DS.hasMany('test-case-run-log')
Finally, I've found the answer of my question.
The problem was that I was using the "underscore" form of the relationships:
"included": [
{
"id": "426",
"type": "test_case_run_log", <= HERE
"attributes": {
"payload": "SCREENSHOT"
},
"relationships": {
"test_case_run": {
"data": {
"id": "83",
"type": "test_case_run" <= HERE
}
}
}
}
]
And, changing pathForType was not sufficient.
So, I made my backend use dashes. And, it worked.

How to remove the sys object from the contentful CDA response?

How can I remove the sys object from the Content Delivery API response for the getEntries method? I was trying to use the select search parameter for querying but it doesn't remove the sys object.
getProducts(query?: object): Promise<Entry<any>[]> {
return this.cdaClient.getEntries(Object.assign({
content_type: 'product',
select: 'fields',
include: 1
}, query))
.then(res => res.items);
Heyooo.
Because of the way how Contentful's linking mechanism work the JSON response of the collection endpoint includes two main parts – items and includes.
{
"items": [
{
"sys": {
"type": "Entry",
"id": "4rJn9OJsBiAKmeoiiw40Ko",
},
"fields": {
"name": "Menu for Humans",
"stickiness": 999.3,
"menuMeal": [
{
"sys": {
"type": "Link",
"linkType": "Entry",
"id": "3HkMtbj6hqcMYEqWIOm6SQ"
}
}
]
}
},
],
"includes": {
"Entry": [
{
"sys": {
"id": "3HkMtbj6hqcMYEqWIOm6SQ",
"type": "Entry",
...
},
"fields": {...}
},
...
}
]
}
The entries in items reference other items from the includes object. The provided SDKs do some magic under the hood to resolve these for you so that you can access fields recursively down the tree (e.g. entry.fields.anotherEntry.fields) – no matter how the response structure looks like.
This is why you unfortunately can't omit the sys property in the JS sdk because it's needed for the link resolution.

Convert Excel file to JSON: design of JSON code check

I want to convert the data from an Excel file to a JSON file. However, I'm not sure about the design of my JSON code (i.e. is it organized in a proper way in order to process it easily?)
I will use this JSON file with D3.js.
This a small part of my Excel file:
I'd like to convert this data into a JSON file in order to use it with D3.js. This is what I have so far:
So my question is: is this a good design (way) for organizing the data in order to use it with D3.js?
This is a sample output:
Thanks in advance!
This is a somewhat subjective question, but from my experience, there is a better way:
Since you're working in d3, you're probably doing something like this:
d3.selectAll('div')
.data(entities)
.enter()
.append('div')
...
So you want entities to be an array. The question is what are your entities? Is there a view where entities are all the countries in the world? Is there a view where entities are all the countries plus all the regions plus the whole world? Or, are all the views going to be simply all the countries in a selected region, not including the region itself?
The unless the JSON structure you're proposing matches the combinations of entities that you plan to display, your code will have to do a bunch of concat'ing and/or filtering of arrays in order to get a single entities array that you can bind to. Maybe that's ok, but it will create some unnecessary amount of coupling between your code and the structure of the data.
From my experience, it turns out that the most flexible way (and also probably the simplest in terms of coding) is to keep the hierarchy flat, like it is in the excel file. So, instead of encoding regions into the hierarchy, just have them in a single, flat array like so:
{
"immigration": [
{
"name": "All Countries"
"values: [
{ "Year": ..., "value": ... },
{ "Year": ..., "value": ... },
...
]
},
{
"name": "Africa"
"values: [
{ "Year": ..., "value": ... },
{ "Year": ..., "value": ... },
...
]
},
{
"name": "Eastern Africa"
"continent": "Africa"
"values": [
{ "Year": ..., "value": ... },
{ "Year": ..., "value": ... },
...
]
},
{
"name": "Burundi"
"continent": "Africa"
"region": "East Africa"
"values": [
{ "Year": ..., "value": ... },
{ "Year": ..., "value": ... },
...
]
},
{
"name": "Djibouti"
"continent": "Africa"
"region": "East Africa"
"values": [
{ "Year": ..., "value": ... },
{ "Year": ..., "value": ... },
...
]
},
...
]
}
Note that even though the array is flat, there is still a hierarchy here -- the region and sub-region properties.
You'll have to do a bit of filtering to extract just the countries/regions you want to show. But that's simpler than traversing the hierarchy you're proposing:
var africanEntities = data.immigration.filter(function(country) {
return country.continent == "Africa";
}); // Includes the region "East Africa"
var justCountries = data.immigration.filter(function(country) {
return country.continent != null && country.region != null;
});
Also, d3 has the awesome d3.nest(), which lets you turn this flat data into hierarchical one with little effort:
var countriesByContinent = d3.nest()
.key(function(d) { return d.continent; })
.map(data.immigration);
var africanEntities = countriesByContinent['Africa'];
Hope that helps....

Categories