2016-06-20 1 views
2

je les suivantes JsonJavascript comment retourner tableau de carte

var myjson = [{ 

      "files": [ 
       { 
        "domain": "d", 
        "units": [ 
         { 
          "key": "key1", 
          "type": "2" 

        }, 
         { 
          "key": "key2", 
          "type": "2" 
        }, 
         { 
          "key": "key3", 
          "type": "2" 
        }] 

      }, 

       { 
        "domain": "d1", 
        "units": [ 
         { 
          "key": "key11", 
          "type": "2" 

        }, 
         { 
          "key": "key12", 
          "type": "2" 
        }, 
         { 
          "key": "key13", 
          "type": "2" 
        }] 

      }] 

      }, 

     { 

      "files": [ 
       { 
        "domain": "d", 
        "units": [ 
         { 
    ...... 

Je veux créer un nouveau tableau de ce tableau JSON. La longueur du tableau sera le nombre de "unités" dans cet objet Json. J'ai donc besoin d'extraire des "unités" et d'ajouter des données à partir d'objets parents.

units: [{ 
     domain: "", 
     type: "", 
     key: "" 
    }, { 
     domain: "", 
     type: "", 
     key: "" 
    }, 
    { 
     domain: "", 
     type: "", 
     key: "" 
    } 
.... 
    ]; 

Je pense que je peux probablement faire quelque chose comme ceci:

var res = []; 

myjson.forEach(function(row) { 
    row.files.forEach(function(tfile) { 
     tfile.units.forEach(function(unit) { 

      var testEntity = { 
       domain: tfile.domain, 
       type : unit.type, 
       key: unit.key 

      }; 

      res.push(testEntity); 

     }); 
    }); 
}); 

Mais il est difficile de lire et ne regarde pas si bon. Je pensais faire quelque chose comme:

var RESULT = myjson.map(function(row) { 
    return row.files.map(function(tfile) { 
     return tfile.units.map(function(unit) { 

      return { 
       domain: tfile.domain, 
       type : unit.type, 
       key: unit.key 

      }; 



     }); 
    }); 
}); 

Mais cela ne fonctionne pas et ne semble pas mieux. Y a-t-il un moyen de le faire, peut-être de façon plus déclarative? espéré Ramda.js pourrait aider.

Est-ce qu'il y a une bonne approche en général pour obtenir des données de n'importe quel json emboîté de manière lisible?

La mise en œuvre quelque chose comme:

nestedjson.findAllOnLastlevel(function(item){ 

return { 
key : item.key, 
type: type.key, 
domain : item.parent.domain} 

}); 

Ou en quelque sorte aplatir cette JSON si toutes les propriétés de tous les parents objets sont déplacés à leafs enfants. myjson.flatten ("files.units")

jsbin http://jsbin.com/hiqatutino/edit?css,js,console

Un grand merci

+0

si vous avez besoin d'une version de travail, que vous avez déjà ou une bonne version à la recherche, ce qui pourrait être accompli avec le style ES6? –

+0

maintenant j'ai une version moche de travail, mais je fais beaucoup de ce "opérations json imbriquées" Pensait à une approche appropriée. Peut-être même une approche générale. Le json que j'ai fourni est simplifié. Cela pourrait être plus profond. De plus, le nouveau "=>" n'est pas disponible dans mon cas. – Ant

+0

Le principal problème est de savoir quelle propriété doit itérer. vous pourriez donner un chemin avec une approche récursive, mais au moins vous avez besoin des propriétés pour se recombiner. –

Répondre

5

La fonction que vous pouvez utiliser ici est fonction de Ramda R.chain plutôt que R.map. Vous pouvez penser à R.chain comme un moyen de mapper sur une liste avec une fonction qui renvoie une autre liste, puis aplatit la liste des listes qui en résulte ensemble.

// get a list of all files 
const listOfFiles = 
    R.chain(R.prop('files'), myjson) 

// a function that we can use to add the domain to each unit 
const unitsWithDomain = 
    (domain, units) => R.map(R.assoc('domain', domain), units) 

// take the list of files and add the domain to each of its units 
const result = 
    R.chain(file => unitsWithDomain(file.domain, file.units), listOfFiles) 

Si vous voulez prendre un peu plus loin, vous pouvez également utiliser R.pipeK qui aide à la composition des fonctions ensemble qui se comportent comme R.chain entre chacune des fonctions données.

// this creates a function that accepts the `myjson` list 
// then passes the list of files to the second function 
// returning the list of units for each file with the domain attached 
const process = pipeK(prop('files'), 
         f => map(assoc('domain', f.domain), f.units)) 

// giving the `myjson` object produces the same result as above 
process(myjson) 
+0

a l'air bon - j'ai simplifié mon json, si j'ai plusieurs (cinq) propriétés qui doivent être associé au même endroit comme domaine? Et plusieurs autres propriétés sur le premier niveau prop1: "valeur", fichiers ": {.... J'ai ajouté ici http://jsbin.com/samilit/edit?css,js,console – Ant

+0

' var résultat = R.pipe ( R.chain (fonction (p) {return R.map (R.assoc ('parent', p), p.files)}, R.chain (fonction (p) {return R.map (R .assoc ('parent', p), p.units)}), R.chain (fonction (k) {return { domaine: k.parent.domaine, prop1: k.parent.parent.prop1, key: k.key}}) ) (myjson) ' – Ant

+0

Ouais, cela nécessiterait d'enfiler les valeurs de propriété en tant qu'état à travers chaque étape, par exemple http://jsbin.com/vepumikuve/1/edit?js,console –

1

Quelque chose comme cela devrait fonctionner. .reduce est un bon pour ce genre de situations.

const allUnits = myjson.reduce((acc, anonObj) => { 
    const units = anonObj.files.map(fileObj => { 
    return fileObj.units.map(unit => { 
     return {...unit, domain: fileObj.domain}) 
    }) 
    return [...acc, ...units] 
}, []) 

Notez que ce tableau dépend à la fois la diffusion et la propagation objet, qui sont ES6 non supportées par chaque plate-forme.

Si vous ne pouvez pas utiliser ES6, voici une implémentation ES5. Pas aussi jolie, mais fait la même chose:

var allUnits = myjson.reduce(function (acc, anonObj) { 
    const units = anonObj.files.map(function(fileObj) { 
    // for each fileObject, return an array of processed unit objects 
    // with domain property added from fileObj 
    return fileObj.units.map(function(unit) { 
     return { 
     key: unit.key, 
     type: unit.type, 
     domain: fileObj.domain 
     } 
    }) 
    }) 
    // for each file array, add unit objects from that array to accumulator array 
    return acc.concat(units) 
}, []) 
+0

J'ai ES5, et aucun moyen de le changer :( – Ant

0

Essayez cette

var myjson = [{ 
 

 
"files": [{ 
 
    "domain": "d", 
 
    "units": [{ 
 
     "key": "key1", 
 
     "type": "2" 
 
    }, { 
 
     "key": "key2", 
 
     "type": "2" 
 
    }, { 
 
     "key": "key3", 
 
     "type": "2" 
 
    }] 
 
    }, 
 
    { 
 
    "domain": "d1", 
 
    "units": [{ 
 
     "key": "key11", 
 
     "type": "2" 
 

 
    }, { 
 
     "key": "key12", 
 
     "type": "2" 
 
    }, { 
 
     "key": "key13", 
 
     "type": "2" 
 
    }] 
 
    } 
 
] 
 
}]; 
 

 
//first filter out properties exluding units 
 
var result = []; 
 
myjson.forEach(function(obj){ 
 
    obj.files.forEach(function(obj2){ 
 
    result = result.concat(obj2.units.map(function(unit){ 
 
     unit.domain = obj2.domain; 
 
     return unit; 
 
    })); 
 
    }); 
 
}); 
 

 
console.log(result);

+0

fonctionne, peut quelque chose qui ne nécessite pas var résultat = []; pourrait être fait? Inmutable manière? Carte renvoie toujours un résultat? Peut-il retourner "type de multiple" – Ant

+0

'domaine' clé est manquée – RomanPerekhrest

+0

@Ant carte à tous les trois niveaux va vous retourner quelque chose comme' [[[{key: 'key1', valeur: '1'}]]] '' et pour surmonter cela, vous devez écrire le code pour accepter des éléments individuels et les concaténer plus tard dans un tableau Comme vous vouliez un code plus court, je ne peux pas le raccourcir :) – gurvinder372

2

Pure JS est très suffisant pour produire le résultat en simples doublures. Je ne toucherais aucune bibliothèque juste pour ce travail. J'ai deux façons de le faire ici. Le premier est une chaîne de reduce.reduce.map et le second est une chaîne de reduce.map.map. Voici le code;

var myjson = [{"files":[{"domain":"d","units":[{"key":"key1","type":"2"},{"key":"key2","type":"2"},{"key":"key3","type":"2"}]},{"domain":"d1","units":[{"key":"key11","type":"2"},{"key":"key12","type":"2"},{"key":"key13","type":"2"}]}]},{"files":[{"domain":"e","units":[{"key":"key1","type":"2"},{"key":"key2","type":"2"},{"key":"key3","type":"2"}]},{"domain":"e1","units":[{"key":"key11","type":"2"},{"key":"key12","type":"2"},{"key":"key13","type":"2"}]}]}], 
 
    units = myjson.reduce((p,c) => c.files.reduce((f,s) => f.concat(s.units.map(e => (e.domain = s.domain,e))) ,p) ,[]); 
 
    units2 = myjson.reduce((p,c) => p.concat(...c.files.map(f => f.units.map(e => (e.domain = f.domain,e)))) ,[]); 
 
    console.log(units); 
 
    console.log(units2);

Pour la compatibilité ES5 je suggère la chaîne reduce.reduce.map car il n'y a pas besoin d'un opérateur de diffusion. Et remplacez les fonctions de flèche avec leurs homologues conventionnels comme celui ci-dessous;

var myjson = [{"files":[{"domain":"d","units":[{"key":"key1","type":"2"},{"key":"key2","type":"2"},{"key":"key3","type":"2"}]},{"domain":"d1","units":[{"key":"key11","type":"2"},{"key":"key12","type":"2"},{"key":"key13","type":"2"}]}]},{"files":[{"domain":"e","units":[{"key":"key1","type":"2"},{"key":"key2","type":"2"},{"key":"key3","type":"2"}]},{"domain":"e1","units":[{"key":"key11","type":"2"},{"key":"key12","type":"2"},{"key":"key13","type":"2"}]}]}], 
 
    units = myjson.reduce(function(p,c) { 
 
     \t      return c.files.reduce(function(f,s) { 
 
     \t      \t      return f.concat(s.units.map(function(e){ 
 
     \t      \t      \t       e.domain = s.domain; 
 
     \t      \t      \t       return e; 
 
     \t      \t      \t       })); 
 
     \t           },p); 
 
     \t     },[]); 
 
console.log(units);