搜索包含值的 json 对象键,然后取消设置它
Posted
技术标签:
【中文标题】搜索包含值的 json 对象键,然后取消设置它【英文标题】:Searching json object key containing value, then unset it 【发布时间】:2012-08-23 04:35:24 【问题描述】:我正在寻找一种方法来搜索 JSON 对象以检查它是否包含给定值,如果存在,则取消设置它。
我的数据结构如下(附注释):
// Search within the 'seats' array for a given 'guestID', if it exists, unset it
tables = [
"_id":
$oid: "one"
,
"seats":[
"guestId":"01" ,
"guestId":"02" ,
"guestId":"03"
]
,
"_id":
$oid: "two"
,
"seats":[
"guestId":"11" ,
"guestId":"12" ,
"guestId":"13"
]
]
我在这个项目中使用下划线,我尝试使用_.pluck(tables, 'seats')
,然后使用 _.foreach,但我不得不嵌套多个 _.foreach 语句来访问席位数组进行搜索,我不确定这是否是最佳实践。有没有我不知道的更简单的方法?
这个数据是从 mongolab REST api 返回的。这是我应该在我的初始 XHR 请求中做的事情,而不是获取一个大对象然后尝试在客户端解析它吗?
如果这是一个 SQL 请求,我将能够执行类似 select tables.seats where guestId = XXX
的操作
【问题讨论】:
您到底在寻找什么?您的输入和期望输出是什么? 如果一张桌子包含所需的座位,您是要删除桌子,还是删除座位? 【参考方案1】:每当我过去遇到这种情况时,递归搜索功能一直是无价的......这是我的一个我躺在身边(我通过添加删除方法扩展它):
function o ( target )
/// if an instance of o has been created, then handle it
if ( this instanceof o )
/// O INSTANCE:
/// an instance of o acts like a reference or pointer
/// to how the value it targets was reached.
this.value = target;
this.key = arguments[1];
this.parent = arguments[2];
this.toString = function() return 'o('+this.key+' = '+this.value+')';
/// if no instance being created fall back to the 'scan object' code
else
/// RECURSIVE CODE:
/// the _ function is responsible for accepting the
/// attributeName and attributeValue search
var _ = function ( key, value, modifier )
var i, v, tar = ( modifier ? modifier.target : target ), items = [];
/// if we are dealing with an o instance, handle slightly differently
if ( tar instanceof o )
for ( i in tar.value )
/// check to see if our current key and value
/// match our search terms
if ( _.test( i, (v=tar.value[i]), key, value ) )
items.push(new o(v, i, tar));
;
;
/// if no o instance treat as a normal object or array
else
for ( i in tar )
if ( (v = tar[i]) )
/// if we are an instance of o, recurse to actually
/// check the items within
if ( v instanceof o )
items = items.concat( _( key, value, target:v ) );
/// check to see if our current key and value match
/// our search terms
else if ( _.test( i, v, key, value ) )
items.push(new o(v, i, tar));
;
;
;
;
/// if in modifier mode, don't rely on storing in scope,
/// return the calculated items instead
if ( modifier )
return items;
else
/// update what we are targeting
target = items;
/// return our underscore function
return _;
;
;
/// FUNCTION DECLARATIONS:
/// a quick test to see if the key and value match (or either or)
_.test = function ( i,v,key,value )
var havekey = ( key !== null && key !== undefined ),
haveval = ( value !== null && value !== undefined ),
passkey = ( havekey && (i == key || key === '*') ),
passval = ( haveval && (v == value || value === '*') );
return ( havekey && haveval && passkey && passval ) ||
( havekey && !haveval && passkey ) ||
( haveval && !havekey && passval );
;
/// calculate the path needed to reach the object within the structure
_.path = function ()
var i = target.length, paths = [], path, cur, last;
while ( i-- )
cur = target[i]; path = [];
do last = cur; if ( cur instanceof o ) path.unshift( cur.key );
while( (cur = cur.parent) );
paths.push(path.join('/'));
;
return ( paths.length == 1 ? paths[0] : paths );
;
/// remove the item we are targeting by stepping back
/// and deleting ourselves from the previous parent
_.remove = function ( removeEntireObject )
var i = target.length, paths, path, cur, last;
while ( i-- )
cur = target[i];
/// remove the object that has the found attribute
if ( removeEntireObject )
if ( cur.parent.parent )
cur.parent.parent.value[cur.parent.key] = null;
delete cur.parent.parent.value[cur.parent.key];
/// otherwise remove only the targeted attribute
else
cur.parent.value[cur.key] = null;
delete cur.parent.value[cur.key];
;
return _;
;
/// a useful function for backwards navigation
_.parent = function ()
var i = target.length, cur, items = [], values = [];
while ( i-- )
cur = target[i];
/// remove the object that has the found attribute
if ( cur && cur.parent )
/// store the values as we go so we can
/// spot and remove duplicated parents
if ( values.indexOf(cur.parent.value) === -1 )
items.push(cur.parent);
values.push(cur.parent.value);
;
target = items;
return _;
/// slimple debugging
_.alert = function ()
var i = target.length, cur;
while ( i-- )
cur = target[i];
alert(cur);
;
return _;
;
return _;
;
;
示例用法:
/// remove only the guestId object with a value '01'
o(tables)('*')('seats')('*')('guestId', '01').remove( true );
或:
/// remove the 'guestIds' object in the first slot for either seat
o(tables)('*')('seats')(0)('guestId', '*').parent().remove();
或:
/// remove all 'guestIds' from the first seat
o(tables)(0)('seats')('*')('guestId').parent().remove();
解释:
您必须始终先致电o(my_object_to_parse)
。
传递一个参数相当于attributeName
搜索。
传递两个参数充当attributeName
和attributeValue
搜索。
*
充当简单的通配符,可用于处理基本数组。
*
可以用作attributeName
或attributeValue
。
每个连续的请求都会在结构中进一步移动一层。
我已经有一段时间没有使用此代码了,因此它可能不是 100% 无错误或最佳的。但是,它似乎适用于您的特定用例……并且它还设法处理了我在测试时扔给它的所有内容。除了.remove()
、.parent()
、.path()
和.alert()
之外,它应该很容易扩展更多方法,并且最好添加一些错误检查。
【讨论】:
以上是关于搜索包含值的 json 对象键,然后取消设置它的主要内容,如果未能解决你的问题,请参考以下文章
PostgreSQL 查询包含特定键值的 json 对象中的行