2011-08-31 27 views
15

¿Hay alguna manera de unir de manera eficiente los datos JSON? Supongamos que tenemos dos conjuntos de datos JSON:Estilo SQL JOIN en datos JSON

{"COLORS":[[1,red],[2,yellow],[3,orange]]} 

{"FRUITS":[[1,apple],[2,banana],[3,orange]]} 

y quiero convertir esto en el siguiente lado del cliente:

{"NEW_FRUITS":[[1,apple,red],[2,banana,yellow],[3,orange,orange]]} 

Tenga en cuenta que habrá miles de registros aquí con estructuras de datos mucho más complejos. jQuery y vainilla javascript están bien. También tenga en cuenta que puede haber colores sin frutas y frutas sin colores.

NOTA: En aras de la simplicidad, digamos que los dos conjuntos de datos están en el mismo orden, pero el segundo conjunto de datos puede tener espacios.

+0

buena pregunta, pero no tiene dos conjuntos de datos JSON, tiene dos objetos de JavaScript; no desea unir datos JSON, desea unir objetos. – nnnnnn

+0

¿Quién dice que son objetos JS? El OP podría estar refiriéndose a dos cadenas JSON. –

+0

Los detalles precisos sobre las diferencias se han perdido en mí, pero puedo decirle que presento una versión muy truncada de lo que estoy trabajando. –

Respuesta

2

No hay forma directa, pero puede escribir una lógica para obtener un objeto combinado como este. Como "manzana, rojo, plátano ..." todos son de cadena, deben estar envueltos en una comilla simple o doble.

Si puede hacer coincidir la matriz de configuración de COLORES y FRUTAS añadiendo valores nulos para elementos faltantes, puede utilizar este enfoque.

Wroking demo

var colors = {"COLORS":[[1,'red'],[2,'yellow'],[3,'orange']]} 

var fruits = {"FRUITS":[[1,'apple'],[2,'banana'],[3,'orange']]} 

var newFruits = {"NEW_FRUITS": [] } 

//Just to make sure both the arrays are of same size, otherwise the logic will break 
if(colors.COLORS.length == fruits.FRUITS.length){ 
    var temp; 
    $.each(fruits.FRUITS, function(i){ 
     temp = this; 
     temp.push(colors.COLORS[i][2]); 
     newFruits.NEW_FRUITS.push(temp); 
    }); 
} 

Alernatively si se puede crear colors y fruits configuraciones como una serie de objetos en lugar de matriz de la matriz puede probar esta solución, que no se preocupan por la secuencia de los elementos pero aún así el tamaño de la matriz debe coincidir con

Trabajando demo

var colors = {"COLORS":[ {"1": 'red'}, { "2": 'yellow'}, {"3":'orange'}]} 

var fruits = {"FRUITS":[ {"1":'apple'}, { "2": 'banana'}, {"3":'orange'}]} 

var newFruits = {"NEW_FRUITS": [] } 

if(colors.COLORS.length == fruits.FRUITS.length){ 
    var temp, first; 
    $.each(fruits.FRUITS, function(i){ 
     for(first in this)break; 
     temp = {}; 
     temp[first] = []; 
     temp[first].push(this[first]); 
     temp[first].push(colors.COLORS[i][first]); 
     newFruits.NEW_FRUITS.push(temp); 
    }); 
} 
+0

Pero la pregunta dice que las matrices pueden no estar en el mismo orden, por lo que debe coincidir con las ID numéricas proporcionadas, no basadas en el índice de matriz. – nnnnnn

+0

He mencionado en mi respuesta probar solo si coinciden. Como van a ser una gran cantidad de elementos, es mejor si evitamos las condiciones tanto como sea posible en el lado del cliente. – ShankarSangoli

+0

Edité la pregunta para decir que están en el mismo orden, ya que agregar una ordenación a varias sentencias de SQL es trivial. –

9

El hecho de que habrá miles de entradas y las claves no están necesariamente ordenadas significa que su mejor opción (al menos para objetos grandes) es clasificar primero por clave. Para objetos de tamaño inferior a aproximadamente 5 aproximadamente, un enfoque de fuerza bruta n^2 debería ser suficiente.

Luego puede escribir el resultado caminando a través de las dos matrices en paralelo, agregando nuevos "registros" a su salida sobre la marcha. Esta idea de ordenar-luego-fusionar es relativamente poderosa y se usa con frecuencia. Si no desea ordenar primero, puede agregar elementos a una cola de prioridad, fusionándose sobre la marcha. El enfoque de ordenar luego combinar es conceptualmente más simple de codificar; si el rendimiento importa, debe hacer algunos perfiles.

Para los colores sin frutas y las frutas sin color, supongo que escribir null para el valor que falta es suficiente. Si la misma clave aparece más de una vez en color o fruta, puede elegir una arbitrariamente o lanzar una excepción.

ADDENDUM Hice un violín también: http://jsfiddle.net/LuLMz/. No hace suposiciones sobre el orden de las claves ni ninguna suposición sobre la longitud relativa de las matrices. Las únicas suposiciones son los nombres de los campos y el hecho de que cada subcampo tiene dos elementos.

7

Alasql biblioteca de JavaScript SQL hace exactamente lo que necesita en una sola línea:

<script src="alasql.min.js"></script> 
<script> 
    var data = { COLORS: [[1,"red"],[2,"yellow"],[3,"orange"]],    
       FRUITS: [[1,"apple"],[2,"banana"],[3,"orange"]]}; 

    data.NEW_FRUITS = alasql('SELECT MATRIX COLORS.[0], COLORS.[1], FRUITS.[1] AS [2] \ 
     FROM ? AS COLORS JOIN ? AS FRUITS ON COLORS.[0] = FRUITS.[0]', 
     [data.COLORS, data.FRUITS]); 
</script> 

Se puede jugar con this example en jsFiddle.

Esta es una expresión SQL, donde:.

  • SELECT - seleccione operador
  • MATRIX - modificador, whci convierte de resultados de matriz de objetos a matriz de matrices
  • colores [0] - primera columna de matriz de COLORES, etc.
  • FRUTAS. 1 AS 2 - la segunda columna de matriz FRUITS se almacenará como tercera columna en el conjunto de registros resultante
  • ¿DESDE? COMO COLORES - matriz de datos a partir de los parámetros denominados COLORES en la declaración SQL
  • ¿ÚNETE? EN ... - participar
  • [data.COLORS, data.FRUITS] - parámetros con arreglos de datos