2
votes

Un moyen élégant et concis de reformater les données JSON en Javascript?

Je reçois un message de résultat JSON au format suivant d'une ancienne requête de base de données que je ne peux pas modifier pour le moment:

{ id: 1, vsm: 2429, color: 5, pmtime: 1549296004, inch: 0  }
{ id: 2, vsm: 2488, color: 4, pmtime: 1549296009, inch: 0  }
{ id: 3, vsm: 1968, color: 4, pmtime: 1549296014, inch: 0  }

}

Je voudrais le reformater en un objet plus utilisable, comme ceci:

{
  "vsm1": "2429",
  "vsm2": "2488",
  "vsm3": "1968",
  "vsm4": "",
  "vsm5": "",
  "vsm6": "",
  "vsm7": "",
  "vsm8": "",
  "vsm9": "",
  "vsm10": "",
  "color1": "5",
  "color2": "4",
  "color3": "4",
  "color4": "0",
  "color5": "0",
  "color6": "0",
  "color7": "0",
  "color8": "0",
  "color9": "0", 
  "color10": "0",
  "p1mtime": "1549296004",
  "p2mtime": "1549296009",
  "p3mtime": "1549296014",
  "p4mtime": "",
  "p5mtime": "",
  "p6mtime": "",
  "p7mtime": "",
  "p8mtime": "",
  "p9mtime": "",
  "p10mtime": "",
  "inch1": "",
  "inch2": "",
  "inch3": "",
  "inch4": "",
  "inch5": "",
  "inch6": "",
  "inch7": "",
  "inch8": "",
  "inch9": "",
  "inch10": "" 

... et ainsi de suite.

Les données entrantes sont actuellement limité à dix de chaque `` section '' (vsm1, vsm2, ... vsm10, color1, color2, ... color10, etc.), donc une boucle statique de quelque sorte sur les dix éléments de chaque section est la façon dont j'ai commencé , mais semblait plutôt laid et certainement pas flexible.

Un extrait intelligent qui gérerait n-nombre d'éléments dans chaque section serait encore mieux au cas où les données dépassent dix éléments, ou tombent à seulement trois (en raison de l'absence de données ou de données élaguées) .

Je pense à quelque chose comme l'utilisation de .forEach (), mais il est vrai que mes compétences en manipulation JSON / objet sont plutôt médiocres, alors je me tourne vers la communauté dans l'espoir que quelqu'un puisse me diriger dans la bonne direction ou connaît une routine / fonction cool et serrée qui réalise ce que je recherche. Merci d'avance pour tout renseignement.


0 commentaires

4 Réponses :


6
votes

Vous pouvez prendre un tableau des clés souhaitées avec un espace réservé pour le numéro en cours et créer un nouvel objet et les pousser vers le jeu de résultats.

.as-console-wrapper { max-height: 100% !important; top: 0; }
var data = { vsm1: "2429", vsm2: "2488", vsm3: "1968", vsm4: "", vsm5: "", vsm6: "", vsm7: "", vsm8: "", vsm9: "", vsm10: "", color1: "5", color2: "4", color3: "4", color4: "0", color5: "0", color6: "0", color7: "0", color8: "0", color9: "0", color10: "0", p1mtime: "1549296004", p2mtime: "1549296009", p3mtime: "1549296014", p4mtime: "", p5mtime: "", p6mtime: "", p7mtime: "", p8mtime: "", p9mtime: "", p10mtime: "", inch1: "", inch2: "", inch3: "", inch4: "", inch5: "", inch6: "", inch7: "", inch8: "", inch9: "", inch10: "" },
    templates = [id => `vsm${id}`, id => `color${id}`, id => `p${id}mtime`, id => `inch${id}`],
    result = [],
    id = 1;

while (templates[0](id) in data) {
    result.push(Object.assign(
        { id },
        ...templates.map(t => ({ [t('')]: +data[t(id)]  || 0 }))
    ));
    id++;
}

console.log(result);

Avec littéraux de modèle

.as-console-wrapper { max-height: 100% !important; top: 0; }
var data = { vsm1: "2429", vsm2: "2488", vsm3: "1968", vsm4: "", vsm5: "", vsm6: "", vsm7: "", vsm8: "", vsm9: "", vsm10: "", color1: "5", color2: "4", color3: "4", color4: "0", color5: "0", color6: "0", color7: "0", color8: "0", color9: "0", color10: "0", p1mtime: "1549296004", p2mtime: "1549296009", p3mtime: "1549296014", p4mtime: "", p5mtime: "", p6mtime: "", p7mtime: "", p8mtime: "", p9mtime: "", p10mtime: "", inch1: "", inch2: "", inch3: "", inch4: "", inch5: "", inch6: "", inch7: "", inch8: "", inch9: "", inch10: "" },
    keys = ['vsm*', 'color*', 'p*mtime', 'inch*'],
    result = [],
    id = 1;

while (keys[0].replace('*', id) in data) {
    result.push(Object.assign(
        { id },
        ...keys.map(k => ({ [k.replace('*', '')]: +data[k.replace('*', id)]  || 0 }))
    ));
    id++;
}

console.log(result);


6 commentaires

ooooh! Je n'ai jamais essayé de créer des modèles, et l'utilisation de .replace () - un espace réservé a également un sens (je l'ai même fait en PHP oh-so-many-lunes-il y a-que-j'ai-oublié). Les deux solutions sont intrigantes! Merci pour les extraits. Je vais dormir dessus et choisir un «gagnant» dans la matinée. :)


Génial, j'ai essayé de comprendre votre code, c'est simple à écrire mais difficile à implémenter.


comment puis-je aider?


J'ai choisi la réponse de Nina pour la nouveauté de la solution et j'ai appris quelque chose de nouveau. Cela ne veut pas dire que les autres réponses fournies ici sont moins valables, créatives ou flexibles. Scott est venu une bonne seconde, et je peux voler cela pour un autre projet connexe. Merci à tous ceux qui ont contribué! :)


je ne comprends pas cette syntaxe while (templates [0] (id) in data) et ce templates.map (t => ({[t ('')]: + data [t (id)] || 0})) . Que signifie le signe + avant la valeur de l'objet?


@tolotrasmile, c'est un unaire plus + , qui convertit ce qui suit en un nombre, comme Number () ou parseFloat () .



2
votes

Essayez ceci, avec oldObject l'objet que vous voulez nettoyer:

var cleanedObject = {};
for (let [key, value] of Object.entries(oldObject)) {
  let index = key.match('[0-9]+');
  cleanedObject[index] = cleanedObject[index] || {};
  cleanedObject[index][key.replace(index, '')] = value;
}

Le résultat sera un objet où cleaningObject ['1'] = {vsm: 2429, couleur: 5, pmtime: 1549296004, inch: ''} , et ainsi de suite.


2 commentaires

C'est un bon début, mais ce serait bien de plier ces identifiants dans l'objet, puis d'utiliser Object.values ​​ pour extraire ce que l'OP recherche. Et vous voudrez peut-être ensuite trier les résultats.


Correct - Je cherche à extraire le numéro des clés (ce que fait JasonR), puis à le réutiliser dans le cadre de l'identifiant «record». Le tri est agréable mais pas obligatoire car ce code d'analyse est exécuté dans le nœud, côté serveur, et le client peut choisir de trier par id ou par couleur (ils représentent une `` priorité '' mappée sur un jeu de couleurs), ou même l'horodatage . J'apprécie toujours la contribution, JasonR! Merci.



1
votes

Cette solution a une flexibilité différente de celle de Nina Sholz. Nina vous permet de faire correspondre n'importe quel style de clé contenant un nombre. Mais cela vous oblige également à ajouter un modèle pour ce faire. Le mien gérera toutes les clés qui ne contiennent qu'une seule série de chiffres mais rien de plus complexe. Mais cela ne vous oblige à rien faire pour gérer ces modèles.

const reformat = data => Object.values(Object.keys(data)
  .reduce(
    (a, k, i, _, d = k.match(/\d+/)[0])  => ({
      ...a, 
      [d]: {...(a[d] || {id: Number(d)}), [k.replace(/\d+/, '')]: data[k]}
    }), {})).sort((a, b) => a.id - b.id)

const data = {"vsm1":"2429","vsm2":"2488","vsm3":"1968","vsm4":"","vsm5":"","vsm6":"","vsm7":"","vsm8":"","vsm9":"","vsm10":"","color1":"5","color2":"4","color3":"4","color4":"0","color5":"0","color6":"0","color7":"0","color8":"0","color9":"0","color10":"0","p1mtime":"1549296004","p2mtime":"1549296009","p3mtime":"1549296014","p4mtime":"","p5mtime":"","p6mtime":"","p7mtime":"","p8mtime":"","p9mtime":"","p10mtime":"","inch1":"","inch2":"","inch3":"","inch4":"","inch5":"","inch6":"","inch7":"","inch8":"","inch9":"","inch10":""}

console.log(reformat(data))

Je ne sais pas si vous avez besoin de l'une ou l'autre sorte de flexibilité, mais ce sont des alternatives intéressantes les unes aux autres.


2 commentaires

Celui-ci dépasse celui de Nina - jamais essayé de modèles mais me semble intéressant - mais ne tient pas vraiment à ce que l'ensemble de résultats soit publié sous forme de chaînes. J'ai juste besoin d'une simple mise en page «nom-clé: numéro» pour que je puisse analyser et faire des calculs sur les valeurs telles quelles sans avoir besoin de les reconvertir en nombres. Je suppose que je pourrais simplement les supprimer du post-traitement en convertissant tout le désordre en une chaîne, extraire les "s et ensuite les analyser en JSON. Merci à tous pour le commentaire! Je choisirai un gagnant après une bonne nuit de sommeil.


La sortie est des chaînes, car l'entrée est des chaînes. Si cela ne vous dérange pas de convertir les chaînes vides en zéros, alors vous pouvez remplacer data [K] par Number (data [k]) , et obtenir des nombres pour tout. De plus, si, comme mentionné dans un commentaire séparé, vous ne vous souciez pas du tri, il est trivial de le supprimer ici.



1
votes

Je vois maintenant que ma réponse est fondamentalement la même que celle de Ninas, je n'ai jamais vu de modèles auparavant, donc c'était cool, mais vu que c'est la première fois que j'ai essayé de répondre à quelque chose ici, je vais simplement la partager de toute façon .

En tant que Ninas, cela peut gérer n'importe quelle longueur de données.

const data = {"vsm1": "2429",
  "vsm2": "2488",
  "vsm3": "1968",
  "vsm4": "",
  "color1": "5",
  "color2": "4",
  "color3": "4",
  "color4": "0",
  "p1mtime": "1549296004",
  "p2mtime": "1549296009",
  "p3mtime": "1549296014",
  "p4mtime": "",
  "inch1": "",
  "inch2": "",
  "inch3": "",
  "inch4": "",
  };


const vsmRegex = new RegExp("(vsm\\d)");
const keys = Object.keys(data);

const result = [];
let id= 1;

for(let i = 0; i < keys.length; i++) {
  if(keys[i].match(vsmRegex)) {
    let object = {
      id: id,
      vsm: Number(data[`vsm${id}`]) || 0,
      color: Number(data[`color${id}`]) || 0,
      pmtime: Number(data[`p${id}mtime`]) || 0,
      inch: Number(data[`inch${id}`]) || 0
    };
    result.push(object);
    id++;
  } else {
    break;
  }
}

console.log(result);


0 commentaires