搜索包含值的json对象键,然后将其取消设置 [英] Searching json object key containing value, then unset it

查看:68
本文介绍了搜索包含值的json对象键,然后将其取消设置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一种搜索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搜索.
  • 传递两个参数充当attributeNameattributeValue搜索.
  • *充当简单的通配符,可用于处理基本数组.
  • *可用作attributeNameattributeValue.
  • 每个后续请求都将层次进一步移入结构.
  • 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 and attributeValue search.
  • The * acts as a simple wildcard which can be useful to handle basic arrays.
  • The * can be used as the attributeName or attributeValue.
  • 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆