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ó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...
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 sectionmergedPosts
it says Spread in the post, do I literally just put the valuepost
… so on does this mean themergedPosts
variable going to be an array of the two combined json files?– Anders KitsonApr 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 QaribouMay 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 QaribouMay 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 KitsonMay 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 KitsonMay 3, 2018 at 22:35
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
concopy
si 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 errorThe 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 luegoconst 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 2xJSON.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 elpostsMeta.json
archivo IE: la URL de la imagen de la imagen forma elpostsMeta
Ese es uno de los principales que necesito para estar en la final.transformedPosts
lostransformedPosts
parece ser solo uno de los archivos json en específico, es elposts.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 sermetaByPostId[post.ID]
voy a arreglar la respuesta– atmin
14 mayo 2018 a las 10:01
Attersson
Contundente al grano para su pregunta. Queremos:
- unir
var a = {/*some json*/}
dentrovar 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.
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