JSON encontrar em JavaScript

Existe uma maneira melhor do que o loop para encontrar dados no JSON ? É para editar e excluir.

for(var k in objJsonResp) { if (objJsonResp[k].txtId == id) { if (action == 'delete') { objJsonResp.splice(k,1); } else { objJsonResp[k] = newVal; } break; } } 

Os dados são organizados como lista de mapas. Gostar:

 [ {id:value, pId:value, cId:value,...}, {id:value, pId:value, cId:value,...}, ... ] 

(Você não está pesquisando por meio de “JSON”, está pesquisando em uma matriz – a sequência JSON já foi desserializada em um gráfico de object, nesse caso, uma matriz.)

Algumas opções:

Use um object em vez de uma matriz

Se você está no controle da geração dessa coisa, tem que ser uma matriz? Porque se não, há uma maneira muito mais simples.

Digamos que estes são seus dados originais:

 [ {"id": "one", "pId": "foo1", "cId": "bar1"}, {"id": "two", "pId": "foo2", "cId": "bar2"}, {"id": "three", "pId": "foo3", "cId": "bar3"} ] 

Você poderia fazer o seguinte em vez disso?

 { "one": {"pId": "foo1", "cId": "bar1"}, "two": {"pId": "foo2", "cId": "bar2"}, "three": {"pId": "foo3", "cId": "bar3"} } 

Então, encontrar a input relevante por ID é trivial:

 id = "one"; // Or whatever var entry = objJsonResp[id]; 

… como está atualizando:

 objJsonResp[id] = /* New value */; 

… e removê-lo:

 delete objJsonResp[id]; 

Isso aproveita o fato de que, em JavaScript, você pode indexar em um object usando um nome de propriedade como uma string – e essa string pode ser um literal, ou pode vir de uma variável como com o id acima.

Colocando em um mapa de identificação para índice

(Idéia idiota, anterior ao anterior. Mantida por razões históricas.)

Parece que você precisa que isso seja uma matriz, caso em que não há realmente uma maneira melhor do que pesquisar na matriz, a menos que você queira colocar um mapa nela, o que você poderia fazer se tivesse controle sobre a geração da matriz. object. Por exemplo, digamos que você tenha isso originalmente:

 [ {"id": "one", "pId": "foo1", "cId": "bar1"}, {"id": "two", "pId": "foo2", "cId": "bar2"}, {"id": "three", "pId": "foo3", "cId": "bar3"} ] 

O código de geração poderia fornecer um mapa de ID para índice:

 { "index": { "one": 0, "two": 1, "three": 2 }, "data": [ {"id": "one", "pId": "foo1", "cId": "bar1"}, {"id": "two", "pId": "foo2", "cId": "bar2"}, {"id": "three", "pId": "foo3", "cId": "bar3"} ] } 

Então, obter uma input para o id na variável id é trivial:

 var index = objJsonResp.index[id]; var obj = objJsonResp.data[index]; 

Isso aproveita o fato de você poder indexar objects usando nomes de propriedades.

É claro que, se você fizer isso, precisará atualizar o mapa quando modificar o array, o que pode se tornar um problema de manutenção.

Mas se você não está no controle da geração do object, ou atualizando o mapa de ids-to-indexes é muito código e / ou um problema de manutenção, então você terá que fazer uma pesquisa de força bruta.

Pesquisa por força bruta (corrigida)

Um pouco OT (embora você tenha perguntado se havia uma maneira melhor :-)), mas seu código for loop através de um array está incorreto. Detalhes aqui , mas você não pode usar for..in para percorrer os índices de array (ou melhor, se você fizer isso, você terá que se esforçar muito para fazer isso); for..in percorre as propriedades de um object , não os índices de um array . Sua melhor aposta com uma matriz não esparsa (e a sua não é escassa) é um loop padrão antigo:

 var k; for (k = 0; k < someArray.length; ++k) { /* ... */ } 

ou

 var k; for (k = someArray.length - 1; k >= 0; --k) { /* ... */ } 

O que você preferir (o último nem sempre é mais rápido em todas as implementações, o que é contra-intuitivo para mim, mas lá estamos nós). (Com um array esparso , você pode usar for..in mas novamente tomando especial cuidado para evitar armadilhas; mais no artigo relacionado acima.)

Usar for..in em uma matriz parece funcionar em casos simples, porque as matrizes têm propriedades para cada um de seus índices e suas outras únicas propriedades padrão ( length e seus methods) são marcadas como não enumeráveis. Mas ele quebra assim que você define (ou um framework define) quaisquer outras propriedades no object array (o que é perfeitamente válido; os arrays são apenas objects com um pouco de manipulação especial em torno da propriedade length ).

Eu me deparei com esse problema para um modelo complexo com vários objects nesteds. Um bom exemplo do que eu estava procurando seria o seguinte: vamos dizer que você tem uma polaroid de si mesmo. E essa foto é então colocada no porta-malas de um carro. O carro está dentro de uma grande checkbox. A checkbox está no porão de um grande navio com muitas outras checkboxs. Eu tive que procurar no porão, olhar nos caixotes, checar o porta-malas e depois procurar por uma foto minha.

Não consegui encontrar nenhuma boa solução online para usar, e usar o .filter() só funciona em matrizes. A maioria das soluções sugeria apenas verificar se o model["yourpicture"] existia. Isso era muito indesejável, porque, a partir do exemplo, isso só procuraria o porão do navio e eu precisava de uma maneira de pegá-los mais adiante na toca do coelho.

Esta é a solução recursiva que fiz. Nos comentários, eu confirmei de TJ Crowder que uma versão recursiva seria necessária. Eu pensei que eu iria compartilhá-lo no caso de alguém se deparar com uma situação complexa semelhante.

 function ContainsKeyValue( obj, key, value ){ if( obj[key] === value ) return true; for( all in obj ) { if( obj[all] != null && obj[all][key] === value ){ return true; } if( typeof obj[all] == "object" && obj[all]!= null ){ var found = ContainsKeyValue( obj[all], key, value ); if( found == true ) return true; } } return false; } 

Isso começará a partir de um determinado object dentro do gráfico e recalculará todos os objects encontrados. Eu uso assim:

 var liveData = []; for( var items in viewmodel.Crates ) { if( ContainsKeyValue( viewmodel.Crates[items], "PictureId", 6 ) === true ) { liveData.push( viewmodel.Crates[items] ); } } 

Que irá produzir uma matriz das checkboxs que continha minha foto.

Zapping – você pode usar este javascript lib; DefiantJS. Não há necessidade de reestruturar dados JSON em objects para facilitar a pesquisa. Em vez disso, você pode pesquisar a estrutura JSON com uma expressão XPath como esta:

  var data = [ { "id": "one", "pId": "foo1", "cId": "bar1" }, { "id": "two", "pId": "foo2", "cId": "bar2" }, { "id": "three", "pId": "foo3", "cId": "bar3" } ], res = JSON.search( data, '//*[id="one"]' ); console.log( res[0].cId ); // 'bar1' 

O DefiantJS estende o object global JSON com um novo método; “search” que retorna array com as correspondências (array vazio se nenhum for encontrado). Você pode experimentar você mesmo colando seus dados JSON e testando diferentes consultas XPath aqui:

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

O XPath é, como você sabe, uma linguagem de consulta padronizada.

Se os dados JSON em sua matriz forem classificados de alguma forma, haverá várias pesquisas que você poderá implementar. No entanto, se você não estiver lidando com muitos dados, provavelmente estará bem com uma operação O (n) aqui (como você fez). Qualquer outra coisa provavelmente seria um exagero.

Se você estiver fazendo isso em mais de um local em seu aplicativo, faria sentido usar um database JSON do lado do cliente porque a criação de funções de pesquisa personalizadas é confusa e menos sustentável do que a alternativa.

Confira ForerunnerDB, que fornece um sistema de database JSON do lado do cliente muito poderoso e inclui uma linguagem de consulta muito simples para ajudá-lo a fazer exatamente o que você está procurando:

 // Create a new instance of ForerunnerDB and then ask for a database var fdb = new ForerunnerDB(), db = fdb.db('myTestDatabase'), coll; // Create our new collection (like a MySQL table) and change the default // primary key from "_id" to "id" coll = db.collection('myCollection', {primaryKey: 'id'}); // Insert our records into the collection coll.insert([ {"name":"my Name","id":12,"type":"car owner"}, {"name":"my Name2","id":13,"type":"car owner2"}, {"name":"my Name4","id":14,"type":"car owner3"}, {"name":"my Name4","id":15,"type":"car owner5"} ]); // Search the collection for the string "my nam" as a case insensitive // regular expression - this search will match all records because every // name field has the text "my Nam" in it var searchResultArray = coll.find({ name: /my nam/i }); console.log(searchResultArray); /* Outputs [ {"name":"my Name","id":12,"type":"car owner"}, {"name":"my Name2","id":13,"type":"car owner2"}, {"name":"my Name4","id":14,"type":"car owner3"}, {"name":"my Name4","id":15,"type":"car owner5"} ] */ 

Disclaimer: Eu sou o desenvolvedor do ForerunnerDB.