JSON在JavaScript中查找

除了循环查找JSON数据,还有更好的方法吗? 这是编辑和删除。

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

数据被安排成地图列表。 喜欢:

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

(您不是通过“JSON”进行search,而是通过数组search – JSONstring已经被反序列化为一个对象图,在这种情况下是一个数组。

一些选项:

使用对象而不是数组

如果你在控制这个东西的生成,它是否必须是一个数组? 因为如果不是的话,那就更简单了。

说这是你的原始数据:

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

你可以做下面的事情吗?

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

然后通过IDfind相关条目是微不足道的:

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

…正在更新它:

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

…并删除它:

 delete objJsonResp[id]; 

这利用了以下事实:在JavaScript中,可以使用属性名称作为string将对象索引到一个对象中,并且该string可以是文字,也可以来自上面的id

放入一个ID到索引的地图

(愚蠢的想法,早于上述,因历史原因而保留)

它看起来像你需要这是一个数组,在这种情况下,没有比search数组更好的方法,除非你想要放置一个地图,如果你有控制的代目的。 比如,说你原来是这样的:

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

生成代码可以提供一个id-to-index映射:

 { "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"} ] } 

然后在variablesid获取id的条目是很简单的:

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

这利用了您可以使用属性名称索引到对象的事实。

当然,如果你这样做,你修改arrays时必须更新地图,这可能会成为一个维护问题。

但是如果你不能控制对象的生成,或者更新IDS到索引的映射过多的代码和/或维护问题,那么你将不得不做一个powershellsearch。

蛮力search(更正)

有点OT(虽然你问是否有更好的方法:-)),但是你的代码循环通过一个数组是不正确的。 细节在这里 ,但是你不能使用for..infor..in数组索引(或者说,如果你这样做的话,你必须特别努力)。 for..in循环对象属性 ,而不是数组索引 。 用非稀疏数组(你的是非稀疏的)最好的select是一个标准的老式循环:

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

要么

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

无论你喜欢什么(后者在所有的实现中并不总是更快,这对我来说是违反直觉的,但是我们是这样)。 (用一个稀疏的数组,你可能会使用for..in但是再次需要特别的努力来避免陷阱;更多的在上面链接的文章中)。

在数组中使用for..in 似乎可以在简单的情况下工作,因为数组具有每个索引的属性,并且唯一的其他默认属性( length及其方法)被标记为不可枚举。 但是,只要您设置(或框架设置)数组对象上的任何其他属性(这是完全有效的;数组只是在length属性周围有一些特殊处理的对象),它会中断。

我遇到了这个问题,一个复杂的模型与几个嵌套的对象。 我正在看的一个很好的例子就是:让我们说你有一个宝丽来自己。 然后把这张照片放到汽车的后备箱里。 汽车在一个大箱子里面。 箱子里装着一个大船和许多其他箱子。 我不得不寻找那个房间,看看箱子,检查箱子,然后寻找我现有的照片。

我找不到任何好的在线解决scheme,使用.filter()只适用于数组。 大多数解决schemebuild议只检查model["yourpicture"]存在。 这是非常不受欢迎的,因为从这个例子来看,这只会search船只的掌握,而我需要一种方法让它们远离兔子洞。

这是我做的recursion解决scheme。 在评论中,我从TJ Crowder证实了recursion版本是必需的。 我想我会分享它,以防万一遇到类似的复杂情况。

 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; } 

这将从图中的一个给定的对象开始,并减lessfind的所有对象。 我这样使用它:

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

这将产生一个包含我的图片的箱子的数组。

切换 – 你可以使用这个JavaScript的lib; DefiantJS。 不需要将JSON数据重构为对象以简化search。 相反,您可以使用这样的XPathexpression式searchJSON结构:

  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' 

DefiantJS用一种新的方法扩展了全局对象JSON; “search”返回数组与匹配(如果没有find空数组)。 你可以通过粘贴你的JSON数据并在这里testing不同的XPath查询来自己尝试一下:

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

正如你所知,XPath是一种标准化的查询语言。

如果数组中的JSON数据以某种方式sorting,则可以执行各种search。 但是,如果你没有处理大量的数据,那么你可能会在这里进行O(n)操作。 其他任何可能会矫枉过正。

如果您在应用程序中的多个位置执行此操作,则使用客户端JSON数据库是有意义的,因为创build自定义searchfunction比替代方法混乱且不易维护。

查看ForerunnerDB,它提供了一个function非常强大的客户端JSON数据库系统,并包含一个非常简单的查询语言,以帮助您完成您正在寻找的内容:

 // 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"} ] */ 

免责声明:我是ForerunnerDB的开发者。