Combinar dos archivos Json exportados desde wordpress

12 minutos de lectura

avatar de usuario
anders kitson

Tengo dos archivos Json que exporté de wordpress que tienen ID correspondientes. Quiero combinarlos en un archivo Json para poder llevarlo al sitio web que estoy creando con Gatsby JS. Uno de los archivos es el posts.json y el otro es postsMeta.json. El post_id en publicacionesMeta corresponde con el ID en Publicaciones

¿Cómo sería mejor fusionar los dos? ¿Puedo ejecutar algún tipo de for bucle en js y ¿cómo lo haría? Estoy en Windows, ¿hay algún tipo de explorador json que pueda ayudarme a hacer esto?

por último, también me gustaría recortar algunos de los campos innecesarios, como post_parent en el publicaciones json y algo como el meta_key en el publicacionesMeta json

Ok, espero que esto sea lo suficientemente claro, gracias de antemano.

Aquí hay un ejemplo de los primeros pares de objetos correspondientes en los dos archivos.

publicaciones.json

{"ID":"19","post_author":"2","post_date":"2010-12-31 23:02:04","post_date_gmt":"2010-12-31 23:02:04","post_content":"Harry Potter was not available for the first sitting of the Halloween Picture. I hope everyone had a safe and fun Halloween. Tomorrow is picture retake day, please send back your previous prints if you want retakes. It is also hot lunch. See You tomorrow!","post_title":"Happy Halloween","post_excerpt":"","post_status":"publish","comment_status":"open","ping_status":"open","post_password":"","post_name":"happy-halloween","to_ping":"","pinged":"","post_modified":"2011-01-03 05:26:11","post_modified_gmt":"2011-01-03 05:26:11","post_content_filtered":"","post_parent":"0","guid":"http:\/\/localhost\/mrskitson.ca_wordpress\/?p=19","menu_order":"0","post_type":"post","post_mime_type":"","comment_count":"1"},

publicacionesMeta.json

{"meta_id":"27","post_id":"19","meta_key":"large_preview","meta_value":"http:\/\/www.mrskitson.ca\/wp-content\/uploads\/2010\/12\/halloween.jpg"},

Actualizar:

este es un intento de resolver este problema con la respuesta actual, puede editar el código allí.

  • Código de muestra muy interesante que su pregunta produjo en las respuestas a continuación, +1 para todos 🙂

    – brasofilo

    10 de mayo de 2018 a las 6:08

  • Cree un nuevo json con los campos que necesita, recorra el primer json verificando cada fila en el segundo json, luego, cuando las claves coincidan, complete la ‘fila’ actual en el nuevo json, luego comience de nuevo en la segunda ‘fila’ en el primer json.

    – WltrRpo

    11 mayo 2018 a las 20:32

¿Cómo sería mejor fusionar los dos?

Lo es obligatorio para combinar los dos archivos/datos JSON?

Porque podría simplemente requerir o cargar los datos JSON desde su secuencia de comandos (o incluso ponerlos en el HTML) y luego para obtener el valor meta de un campo/clave meta específico, esto function podría hacer eso:

// `single` has no effect if `meta_key` is empty.
function getPostMeta( post_id, meta_key, single ) {
    let id = String( post_id ),
        pm = [];
    postsMeta.map( m => {
        let a = ( ! meta_key ) ||
            ( meta_key === m.meta_key );

        if ( a && id === m.post_id ) {
            pm.push( m );
        }
    });

    let meta = {},
        mk = {};
    pm.map( m => {
        let k = m.meta_key, v;

        if ( undefined === meta[ k ] ) {
            meta[ k ] = m.meta_value;
        } else {
            v = meta[ k ];
            if ( undefined === mk[ k ] ) {
                meta[ k ] = [ v ];
                mk[ k ] = 1;
            }

            meta[ k ].push( m.meta_value );
            m[ k ]++;
        }
    });

    pm = null;
    mk = meta_key ? mk[ meta_key ] : null;

    if ( mk ) {
        return single ?
            meta[ meta_key ][0] : // Returns a single meta value.
            meta[ meta_key ];     // Returns all the meta values.
    }

    return meta_key ?
        meta[ meta_key ] : // Returns the value of the `meta_key`.
        meta;              // Or returns all the post's meta data.
}

Los datos que usé para la prueba: (tomar nota de la postsMeta en lo de arriba/getPostMeta() función)

// Array of `post` objects.
const posts = [{"ID":"19","post_author":"2","post_date":"2010-12-31 23:02:04","post_date_gmt":"2010-12-31 23:02:04","post_content":"Harry Potter was not available for the first sitting of the Halloween Picture. I hope everyone had a safe and fun Halloween. Tomorrow is picture retake day, please send back your previous prints if you want retakes. It is also hot lunch. See You tomorrow!","post_title":"Happy Halloween","post_excerpt":"","post_status":"publish","comment_status":"open","ping_status":"open","post_password":"","post_name":"happy-halloween","to_ping":"","pinged":"","post_modified":"2011-01-03 05:26:11","post_modified_gmt":"2011-01-03 05:26:11","post_content_filtered":"","post_parent":"0","guid":"http:\/\/localhost\/mrskitson.ca_wordpress\/?p=19","menu_order":"0","post_type":"post","post_mime_type":"","comment_count":"1"}];

// Array of `meta` objects.
const postsMeta = [{"meta_id":"27","post_id":"19","meta_key":"large_preview","meta_value":"http:\/\/www.mrskitson.ca\/wp-content\/uploads\/2010\/12\/halloween.jpg"},{"meta_id":"28","post_id":"19","meta_key":"many_values","meta_value":"http:\/\/facebook.com"},{"meta_id":"29","post_id":"19","meta_key":"many_values","meta_value":"http:\/\/twitter.com"},{"meta_id":"30","post_id":"19","meta_key":"many_values","meta_value":"http:\/\/linkedin.com"}];

Ejemplos: (ver este violín para demostración)

// In these examples, we are retrieving the meta value for the post #19 (i.e. ID is 19).

// Retrieve a single value.
// Returns mixed; string, number, etc.
let url = getPostMeta( 19, 'large_preview', true );
console.log( url );

// Retrieve all meta values.
// Always returns an array of values.
let ms = getPostMeta( 19, 'many_values' );
console.log( ms, ms[0] );

// Retrieve all meta data.
// Always returns an object with meta_key => meta_value pairs. I.e. { key => value, ... }
let ma = getPostMeta( 19 );
console.log( ma, ma.large_preview, ma.many_values[0] );

Pero si realmente debe combinar los datos JSON, puede hacerlo: (nuevamente, vea la demostración en el mismo violín)

// Here we modify the original `posts` object.
posts.map( p => {
    // Add all the post's meta data.
    p.meta = getPostMeta( p.ID );

    // Delete items you don't want..
    delete p.post_parent;
    delete p.menu_order;
    // delete ...;
});

console.log( JSON.stringify( posts[0].meta ) ); // posts[0].meta = object
console.log( posts[0].post_parent, posts[0].menu_order ); // both are undefined

Y luego, si desea copiar y pegar el nuevo/fusionado datos JSON:

JSON.stringify( posts );

Pero si realmente solo quiere hacer algo con el meta de la publicación, puede recorrer el posts objetar y hacer la cosa; p.ej:

// Here the original `posts` object is not modified, and that we don't
// (though you can) repeatedly call `getPostMeta()` for the same post.
posts.map( p => {
    // Get all the post's meta data.
    let meta = getPostMeta( p.ID );

    // Do something with `meta`.
    console.log( meta.large_preview );
});

console.log( JSON.stringify( posts[0].meta ) ); // posts[0].meta = undefined
console.log( posts[0].post_parent, posts[0].menu_order ); // both still defined

// posts[0].meta wouldn't be undefined if of course posts[0] had a `meta` item,
// which was set in/via WordPress...

avatar de usuario
Josh de Qaribú

Si puede hacer esto en js, hay un enfoque bastante fácil usando Array#map. Si simplifica su pregunta, realmente está preguntando cómo agregar estos metadatos debajo de cada entrada en las publicaciones y obtener solo los campos que desea.

Supongo que posts.json es en realidad una matriz (por ejemplo, [{"ID":"19"....).

// Load these server-side, fetch them remotely, copy-paste, etc.
// I'll require them here for simplicity
const posts = require('./posts.json');
const postsMeta = require('./postsMeta.json');

// Build a Map so we can quickly look up the metas by post_id
// Extract what we need by destructuring the args
const metaByPost = postsMeta.reduce((a, {
  post_id: id,
  meta_value: value,
}) => a.set(id, {
  value,
  /* anything else you want in here */,
}), new Map());

const mergedPosts = posts.map(post => ({
  // Spread in the post
  ...post,
  // Spread in the meta content
  ...metaByPost.get(post.ID),
  // Undefine the props we don't want
  post_parent: undefined,
}));

I don’t love manually setting stuff to undefined — I think it’s nicer to explicitly say what props you’re going to include, instead of loading everything and undefining certain props.

  • A little stuck here already. If i need to load these files server side, I am thinking to use meteor place them in the server folder and import them by path, or do I still use the const posts format I also I don’t know what to put in the section mergedPosts it says Spread in the post, do I literally just put the value post… so on does this mean the mergedPosts variable going to be an array of the two combined json files?

    – Anders Kitson

    Apr 30, 2018 at 22:52

  • @AndersKitson take a look at this for more info on spreads: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…

    – Josh from Qaribou

    May 1, 2018 at 1:56

  • What that code’s doing is taking the properties in post, the properties in the meta content for that post, and building a new object of them both put together. Object props always are set to their last one, so post_parent: undefined will set it to undefined if it comes last.

    – Josh from Qaribou

    May 1, 2018 at 1:57

  • Ok so the ... is the actual spread syntax? I assumed you put that in as a fill in the missing part. Also when you say load these server side? Can I do that in Node js? Or in a framework like meteor, or do you suggest another way of doing so?

    – Anders Kitson

    May 1, 2018 at 2:09

  • I tried running this on glitch on the server side you can see it all here glitch.com/edit/#!/join/ca634d31-d3eb-4fe0-a8fb-cce34f4d862c I am getting a Map is not defined error

    – Anders Kitson

    May 3, 2018 at 22:35

user avatar
atmin

Try this snippet directly in the Chrome DevTools console:

(function(
  postsUrl="https://cdn.glitch.com/61300ea6-6cc4-4cb6-a62f-31adc62ea5cc%2Fposts.json?1525386749382",
  metaUrl="https://cdn.glitch.com/61300ea6-6cc4-4cb6-a62f-31adc62ea5cc%2Fpostmeta.json?1525386742630"
) {
  Promise.all([
    fetch(postsUrl).then(r => r.json()),
    fetch(metaUrl).then(r => r.json()),
  ]).después(([postsResponse, metaResponse]) => { // Inspeccionó la respuesta JSON real para generar la estructura de datos const posts = postsResponse[2].datos;  const meta = metaRespuesta[2].datos;  const metaByPostId = meta.reduce((acum, el) => { acum[el.post_id] = el;  volver acumular;  }, {});  const transformedPosts = posts.map(post => { const merged = { ...post, ...(metaByPostId[post.ID] ||  {}), };  eliminar fusionado.post_parent;  // elimine cualquier otro campo que no desee en el resultado devuelve fusionado;  });  console.log(publicaciones transformadas);  });  })();
  • reemplace las URL en consecuencia, usé las del ejemplo de Glitch aquí
  • como se comentó, los datos reales están enterrados en response[2].data. Use la pestaña Red / Vista analizada para ver la estructura
  • reemplazar console.log con copysi desea que el resultado se copie en el portapapeles, en lugar de registrarlo en la consola

  • Hola, gracias por la ayuda, estoy recibiendo un TypeError: meta is undefined cuando se ejecuta esto localmente. Intenté ejecutarlo en Glitch pero recibí un error The page’s settings blocked the loading of a resource Tengo alguna idea.

    –Anders Kitson

    10 de mayo de 2018 a las 2:10

  • Lo más probable es que signifique la solicitud de metaUrl falla y luego const meta = metaResponse[2].data falla Puede averiguarlo observando Devtools / Network. Podría ser una extensión del navegador, prueba la sesión de incógnito. Acabo de probar en Chrome y funciona para mí. Alternativamente, obtenga solo la función interna (const posts = JSON.parse('<your data here >'); const meta = JSON.parse('<meta data>'); ........ console.log(...);nota añadida 2x JSON.parse) y ejecútelo, para omitir la red.

    – atmin

    11 de mayo de 2018 a las 7:40


  • Ok, eso pareció funcionar, sin embargo, no veo el meta_value desde el postsMeta.json archivo IE: la URL de la imagen de la imagen forma el postsMeta Ese es uno de los principales que necesito para estar en la final. transformedPosts los transformedPosts parece ser solo uno de los archivos json en específico, es el posts.json no la fusión de los dos.

    –Anders Kitson

    12 mayo 2018 a las 21:36

  • oh, tienes razón, esto es un error, metaByPostId[post.post_id] debiera ser metaByPostId[post.ID]voy a arreglar la respuesta

    – atmin

    14 mayo 2018 a las 10:01

avatar de usuario
Attersson

Contundente al grano para su pregunta. Queremos:

  • unir var a = {/*some json*/} dentro var b = {/*another json*/}
  • recortar campos en var exclusions = ["post_parent","meta_key"]

Combinar los JSON

Primero, necesitamos poblar a y b. Sus JSON se pueden analizar en objetos Javascript con JSON.parse():

let a = JSON.parse(/*JSON here*/);
let b = JSON.parse(/*JSON here*/);

Debido a cómo se definen las propiedades en Javascript, si define una propiedad nuevamente, la segunda definición sobrescribirá la primera. Sus JSONS contienen solo cadenas como claves y cadenas como valores, por lo que una copia superficial será suficiente. Objeto.assign() copiará todas las propiedades (campo y valores) en el primer argumento y devolverá el Objeto final. Por lo tanto, esto fusionará a en b, suponiendo que tengan claves diferentes, de lo contrario, los valores en b sobrescribirán los valores en a:

a = Object.assign(a,b);

De lo contrario, si no están disjuntos, debe definir alguna política sobre cómo unirse, por ejemplo, puede priorizar uno. A continuación, mantenemos los valores en un lugar:

a = Object.assign(b,a);

Ya que mencionaste un for círculo, la línea de abajo hace lo mismo que las dos líneas de código de arriba y también le permitirá mostrarle un ejemplo sobre cómo escribir su propia expresión lambda personalizada:

Object.keys(a).forEach(k=>b[k]=b[k]?b[k]:a[k]);

no deseo tocar a y b? Crear un tercer objeto c.

let c = Object.assign({},a,b)

Por último (espere hasta que se complete el paso de recorte a continuación) JSON.stringify() convertirá su objeto fusionado nuevamente en JSON.

Recortar exclusiones

Siguiendo el tercer ejemplo, tenemos c combinado con todos los campos.

Primero un pequeño truco tomado de aquí:

Object.filter = (obj, predicate) => Object.keys(obj)
    .filter( key => predicate(obj[key]))
    .reduce( (res, key) => (res[key] = obj[key], res), {} );

Ahora los objetos, al igual que las matrices, tienen un prototipo de filtro, con un prototipo de objeto extendido. Realmente no es la mejor práctica, ya que esto extenderá todos los objetos, pero esta función funciona bastante bien con respecto a la semántica de Javascript y este ejemplo sirve como una oportunidad para mantener un código elegante de estilos Javascript:

c = Object.filter(c, key=> !exclusions.includes(key) );

Voit-lá, listo.

En cuanto a Object.filter() definido, utiliza Matriz.filtro() y Array.reduce() . Haga clic para referencia, para su conveniencia.

¿Ha sido útil esta solución?