2011-12-15 14 views
15

Tengo una matriz de objetos homogéneos como tal;búsqueda JS en valores de objeto

[ 
    { 
    "foo" : "bar", 
    "bar" : "sit" 
    }, 
    { 
    "foo" : "lorem", 
    "bar" : "ipsum" 
    }, 
    { 
    "foo" : "dolor", 
    "bar" : "amet" 
    } 
] 

me gustaría buscar los valores de estos objetos (no las llaves) con una palabra clave, y devolver una matriz de objetos que contienen la palabra clave en cualquiera de los valores.

Entonces, por ejemplo, con una palabra clave r, obtendría todos los objetos ("baR" en el objeto # 1, "loRem" en el objeto # 2 y "doloR" en el objeto # 3). Con una palabra clave lo, obtendría los objetos 2 y 3 ("LOrem" y "doLOr"), con a, obtendría los objetos 1 y 3 ("bAr" y "Amet"). Sin embargo, con la palabra clave foo, obtendría una matriz vacía, ya que "foo" es una clave y no se encuentra en ninguno de los valores (a diferencia de "barra") ... se entiende la idea.

¿Cómo voy a hacer esto? ¡Muchas gracias por adelantado!

+0

Si estás usando jQuery, entonces es un posible duplicado de http://stackoverflow.com/questions/5288833/how-to-search-json-tree-with-jquery –

Respuesta

30

algo como esto:

var objects = [ 
    { 
    "foo" : "bar", 
    "bar" : "sit" 
    }, 
    { 
    "foo" : "lorem", 
    "bar" : "ipsum" 
    }, 
    { 
    "foo" : "dolor", 
    "bar" : "amet" 
    } 
]; 

var results = []; 

var toSearch = "lo"; 

for(var i=0; i<objects.length; i++) { 
    for(key in objects[i]) { 
    if(objects[i][key].indexOf(toSearch)!=-1) { 
     results.push(objects[i]); 
    } 
    } 
} 

La matriz de resultados contendrá todos los objetos emparejados.

Si busca 'lo', el resultado será como:

[{ foo="lorem", bar="ipsum"}, { foo="dolor", bar="amet"}] 

NUEVA VERSIÓN - código de las guarniciones Añadido, código para asegurar que no duplicados en conjunto de resultados.

function trimString(s) { 
    var l=0, r=s.length -1; 
    while(l < s.length && s[l] == ' ') l++; 
    while(r > l && s[r] == ' ') r-=1; 
    return s.substring(l, r+1); 
} 

function compareObjects(o1, o2) { 
    var k = ''; 
    for(k in o1) if(o1[k] != o2[k]) return false; 
    for(k in o2) if(o1[k] != o2[k]) return false; 
    return true; 
} 

function itemExists(haystack, needle) { 
    for(var i=0; i<haystack.length; i++) if(compareObjects(haystack[i], needle)) return true; 
    return false; 
} 

var objects = [ 
    { 
    "foo" : "bar", 
    "bar" : "sit" 
    }, 
    { 
    "foo" : "lorem", 
    "bar" : "ipsum" 
    }, 
    { 
    "foo" : "dolor blor", 
    "bar" : "amet blo" 
    } 
]; 

function searchFor(toSearch) { 
    var results = []; 
    toSearch = trimString(toSearch); // trim it 
    for(var i=0; i<objects.length; i++) { 
    for(var key in objects[i]) { 
     if(objects[i][key].indexOf(toSearch)!=-1) { 
     if(!itemExists(results, objects[i])) results.push(objects[i]); 
     } 
    } 
    } 
    return results; 
} 

console.log(searchFor('lo ')); 
+1

Editó el ciclo for un poco. Ahora, si configuras en Search para 'lo', la salida será: [{foo = "lorem"}, {foo = "dolor"}] – techfoobar

+0

Esto es lo más cercano, ya que las otras funciones devuelven matrices de cadenas, y esto regresa matrices de objetos. Sin embargo, los objetos solo contienen el valor coincidente, mientras que debe contener el objeto original completo. ¿Podrías modificar tu script para reflejar esto? –

+1

He actualizado mi respuesta. Espero que esto sea lo que intentabas lograr. – techfoobar

2
var search(subject, objects) { 

    var matches = []; 
    var regexp = new RegExp(subject, 'g'); 

    for (var i = 0; i < objects.length; i++) { 
     for (key in objects[i]) { 
      if (objects[i][key].match(regexp)) matches.push(objects[i][key]); 
     } 
    } 
    return matches; 
}; 

var items = [ 
    { 
    "foo" : "bar", 
    "bar" : "sit" 
    }, 
    { 
    "foo" : "lorem", 
    "bar" : "ipsum" 
    }, 
    { 
    "foo" : "dolor", 
    "bar" : "amet" 
    } 
]; 

search('r', items); // ["bar", "lorem", "dolor"] 
+1

u tiene un error. 'búsqueda (asunto, objetos)' ... – vsync

+0

@vsync: gracias :) –

5

La función search devolverá todos los objetos que contienen un valor que tiene contiene la consulta de búsqueda

function search(arr, s){ 
 
    var matches = [], i, key; 
 
    
 
    for(i = arr.length; i--;) 
 
     for(key in arr[i]) 
 
      if(arr[i].hasOwnProperty(key) && arr[i][key].indexOf(s) > -1) 
 
       matches.push(arr[i]); // <-- This can be changed to anything 
 

 
    return matches; 
 
}; 
 

 
// dummy data 
 
var items = [ 
 
     { 
 
     "foo" : "bar", 
 
     "bar" : "sit" 
 
     }, 
 
     { 
 
     "foo" : "lorem", 
 
     "bar" : "ipsum" 
 
     }, 
 
     { 
 
     "foo" : "dolor", 
 
     "bar" : "amet" 
 
     } 
 
]; 
 
    
 
var result = search(items, 'lo'); // search "items" for a query value 
 
console.log(result); // print the result

+0

esto es rápido, no hay expresiones regulares, Y un cheque para asegurarse no, no hay claves prototipo con 'hasOwnProperty'. – vsync

+0

rápido para buscar contenido en todas las propiedades clave, –

2

Aquí está la respuesta en el 100% PURO JavaScript:

<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
<title></title> 
<script type="text/javascript"> 

var mySet = [ 
    { 
    "foo" : "bar", 
    "bar" : "sit" 
    }, 
    { 
    "foo" : "lorem", 
    "bar" : "ipsum" 
    }, 
    { 
    "foo" : "dolor", 
    "bar" : "amet" 
    } 
]; 

function queryObject(needle, set){ 
    var results = new Array(); 
    for(index=0;index<set.length;index++){ 
     for(key in set[index]){ 
      if(set[index][key].indexOf(needle) > -1){ 
       results.push(set[index]); 
      } 
     } 
    } 

    if(results.length){ 
     return JSON.stringify(results); 
    }else{ 
     return "No match!"; 
    } 
} 

</script> 
</head> 
<body> 
<form> 
    <input type="text" id="prompt" onFocus="this.value='';" value="Type your query HERE" size="20" onKeyDown="document.getElementById('submit').disabled = false;"> 
    <input id="submit" type="button" value="Find in Object" onClick="var prompt=document.getElementById('prompt'); if(prompt.value){document.getElementById('output').innerHTML = queryObject(prompt.value, mySet);}else{prompt.value='Type your query HERE';}" disabled="disabled"> 
    <div id="output"></div> 
</form> 
</body> 
</html> 

Hay, por supuesto, formas más sofisticadas de atravesar su objeto utilizando JQuery, pero este es el concepto básico.

¡Salud!

* EDIT: Disculpe, no leí su pregunta con cuidado y modifiqué el código para devolver una matriz de objetos como había solicitado.

+0

Si desea que la función sea más genéricamente dinámica, eliminará la declaración de conjunto de variables y la pasará a la función como un argumento en su lugar; es decir: 'function queryObject (needle, set)' – lincolnberryiii

+1

Disculpe, no leí su pregunta con cuidado y modifiqué el código para devolver una matriz de objetos tal como lo había solicitado. – lincolnberryiii

2

Puede usar este javascript lib, DefiantJS (http://defiantjs.com), con el que puede filtrar coincidencias utilizando XPath en estructuras JSON. Para ponerlo en código JS:

var data = [ 
     { "foo": "bar", "bar": "sit" }, 
     { "foo": "lorem", "bar": "ipsum" }, 
     { "foo": "dolor", "bar": "amet" } 
    ], 
    res1 = JSON.search(data, '//*[contains(name(), 'r')]/..'), 
    res2 = JSON.search(data, '//*[contains(., 'lo')]'); 

/* 
res1 = [ 
    { "foo": "bar", "bar": "sit" }, 
    { "foo": "lorem", "bar": "ipsum" }, 
    { "foo": "dolor", "bar": "amet" } 
] 
*/ 

/* 
res2 = [ 
    { "foo": "lorem", "bar": "ipsum" }, 
    { "foo": "dolor", "bar": "amet" } 
] 
*/ 

Aquí es un violín de trabajo;
http://jsfiddle.net/hbi99/2kHDZ/

DefiantJS amplía el objeto global con el método "búsqueda" y devuelve una matriz con coincidencias (matriz vacía si no se encontraron coincidencias).Puede probar las consultas lib y XPath XPath utilizando el evaluador aquí:

http://www.defiantjs.com/#xpath_evaluator

3

Como Javascripter Lv. 1 Acabo de aprender a buscar cadenas en los objetos con esto:

function isThere(a_string, in_this_object) 
{ 
    if(typeof a_string != 'string') 
    { 
     return false; 
    } 

    for(var key in in_this_object) 
    { 
     if(typeof in_this_object[key] == 'object' || typeof in_this_object[key] == 'array') 
     { 
      return isThere(a_string, in_this_object[key]) 
     } 
     else if(typeof in_this_object[key] == 'string') 
     { 
      if(a_string == in_this_object[key]) 
      { 
       return true; 
      } 
     } 
    } 

    return false; 
} 

lo que se es lejos de ser perfecto, pero es útil.

Siéntase libre de comentar para mejorar esto.

+0

Cogí el tuyo y lo usé para recorrer un objeto observable de ko. Tuve que hacer cambios, pero funcionó. THanks – boca

0

A continuación compartida de propiedad específica dada

searchContent:function(s, arr,propertyName){ 
      var matches = []; 
      var propertyNameString=this.propertyNameToStr(propertyName); 
      for (var i = arr.length; i--;){ 
       if((""+Object.getOwnPropertyDescriptor(arr[i], propertyNameString).value).indexOf(s) > -1) 
        matches.push(arr[i]); 
      } 
      return matches; 
     }, 
    propertyNameToStr: function (propertyFunction) { 
      return /\.([^\.;]+);?\s*\}$/.exec(propertyFunction.toString())[1]; 
    } 

// uso de la siguiente manera

result=$localStorage.searchContent(cabNo,appDataObj.getAll(),function() { dummy.cabDriverName; }) 
18

Todas las otras respuestas viejas utilizan un bucle en el moderno Javascript Object.keys. Combina eso con algunos, incluye y filtra y es un poco más agradable.

var a = [{ 
 
    name: 'xyz', 
 
    grade: 'x' 
 
}, { 
 
    name: 'yaya', 
 
    grade: 'x' 
 
}, { 
 
    name: 'x', 
 
    frade: 'd' 
 
}, { 
 
    name: 'a', 
 
    grade: 'b' 
 
}]; 
 

 
function filterIt(arr, searchKey) { 
 
    return arr.filter(function(obj) { 
 
    return Object.keys(obj).some(function(key) { 
 
     return obj[key].includes(searchKey); 
 
    }) 
 
    }); 
 
} 
 

 
console.log("find 'x'", filterIt(a,"x")); 
 
console.log("find 'a'", filterIt(a,"a")); 
 
console.log("find 'z'", filterIt(a,"z"));

O con ES6

function filterIt(arr, searchKey) { 
    return arr.filter(obj => Object.keys(obj).some(key => obj[key].includes(searchKey))); 
} 
+0

Con este código de @epascarello puede encontrar un objeto que tenga una clave que contenga la búsquedaKey, pero si está buscando una coincidencia total, debe cambiar la función de prueba de "algún" método usando "===" en su lugar "incluye ": algunos (clave => obj [clave] === searchKey) – DrWaky

0

Esta es una propoosal que utiliza la clave si se da, o todas las propiedades del objeto para la búsqueda de un valor.

function filter(array, value, key) { 
 
    return array.filter(key ? function (a) { 
 
     return a[key] === value; 
 
    } : function (a) { 
 
     return Object.keys(a).some(function (k) { 
 
      return a[k] === value; 
 
     }); 
 
    }); 
 
} 
 

 
var a = [{ name: 'xyz', grade: 'x' }, { name: 'yaya', grade: 'x' }, { name: 'x', frade: 'd' }, { name: 'a', grade: 'b' }]; 
 

 

 
console.log(filter(a, 'x')); 
 
console.log(filter(a, 'x', 'name'));
.as-console-wrapper { max-height: 100% !important; top: 0; }

0

Sólo otra variación utilizando ES6, esto es lo que yo uso.

// searched keywords  
const searchedWord = "My searched exp"; 

// array of objects 
let posts = [ 
    { 
     text_field: "lorem ipsum doleri imet", 
     _id: "89789UFJHDKJEH98JDKFD98" 
    }, 
    { 
     text_field: "ipsum doleri imet", 
     _id: "JH738H3JKJKHJK93IOHLKL" 
]; 

// search results will be pushed here 
let matches = []; 

// regular exp for searching 
let regexp = new RegExp(searchedWord, 'g'); 

// looping throuth posts to fing the word 
posts.forEach((post) => { 
    if (post["text_field"].match(regexp)) matches.push(post); 
}); 
Cuestiones relacionadas