搜索包含值的json对象键,然后将其取消设置 [英] Searching json object key containing value, then unset it
问题描述
我正在寻找一种搜索JSON对象的方法,以检查它是否包含给定值,如果存在,则将其取消设置.
I'm looking for a way to search a JSON object to check if it contains a given value, and if it exists, then unset it.
我的数据结构如下(并附有解释):
My data is structured as follows (commented with explanation):
// 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语句来访问seats数组以进行搜索,但我不确定是否这是最佳做法.有一种我不知道的简单方法吗?
I am using underscore for this project, and I've tried using _.pluck(tables, 'seats')
and then _.foreach but I was having to nest multiple _.foreach statements to access the seats array for searching, and I'm not sure if that's a best practice or not. Is there an easier way that I'm not aware of?
此数据是从mongolab REST API返回的.是我在最初的XHR请求中应该做的事情,而不是获取一个大对象然后尝试通过客户端对其进行解析?
This data is being returned from the mongolab REST api. Is this something I should be doing in my initial XHR request, rather than getting a large object and then trying to parse through it client-side?
如果这是一个SQL请求,我将能够执行类似select tables.seats where guestId = XXX
If this were an SQL request I'd just be able to do something like select tables.seats where guestId = XXX
推荐答案
在过去遇到这种情况时,递归搜索功能始终是无价之宝...这是我躺在这里的一个(我通过添加remove方法对其进行了扩展):
Whenever I've come across these kinds of situations in the past, a recursive search function has always been invaluable... here's one of mine I had lying around (I extended it by adding a remove method):
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
. - 每个后续请求都将层次进一步移入结构.
- You must always start by calling
o(my_object_to_parse)
. - Passing one parameter acts as an
attributeName
search. - Passing two parameters acts as an
attributeName
andattributeValue
search. - The
*
acts as a simple wildcard which can be useful to handle basic arrays. - The
*
can be used as theattributeName
orattributeValue
. - Each successive request moves one level further into the structure.
我已经有一段时间没有使用此代码了,因此它可能不是100%无错误或最佳的.但是,它似乎适用于您的特定用例...并且它还可以处理我在测试时所扔的所有内容.使用.remove()
,.parent()
,.path()
和.alert()
以外的更多方法进行扩展应该足够容易,并且最好添加一些错误检查.
I haven't used this code in a while, so it may not be 100% bug free or optimal. However it seems to work for your particular use case... and it also managed to handle everything I threw at it whilst testing. It should be easy enough to extend with more methods beyond .remove()
, .parent()
, .path()
and .alert()
and it might be best to add in some error checking.
这篇关于搜索包含值的json对象键,然后将其取消设置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!