我正在使用underscore-query,它需要传入一个JSON对象来定义所有搜索子句。我需要通过一个循环构建对象,该循环从接口(interface)读取搜索值。我正在获取所有搜索值,但是我需要将它们转换为查询子句格式。这是一个示例循环:

var filterArray = [];
var filterObject = {};
for (var key in $scope.mpsfilters) {
    if ($scope.mpsfilters.hasOwnProperty(key)) {
        var keyparts = key.split('_');
        filterArray.push({
            $and: {
                "attribute_id": keyparts[0],
                "type": keyparts[1],
                "display_value": {$lte: $scope.mpsfilters[key].range_top, $gte: $scope.mpsfilters[key].range_bottom}
            }
        });
    }
}

for (var i = 0; i < filterArray.length; i++) {
    var filterStep = jQuery.extend({},filterObject, filterArray[i]);
    filterObject = filterStep;
}

我需要的最终结果应如下所示:
{
    $and: {
        "attribute_id": 2422,
        "type": "max",
        "display_value": {
            $lte: 200,
            $gte: 0.3
        }
    },
    $and: {
        "attribute_id": 2421,
        "type": "typ",
        "display_value": {
            $lte: 150,
            $gte: 50
        }
    }
    $and: {
        "attribute_id": 2750,
        "type": "min",
        "display_value": {
            $lte: 17,
            $gte: 2
        }
    }
}

我有两个使这个问题变得复杂的问题:
  • 使用jQuery.extend(),angular.extend(),angular.merge()等的所有示例仅将两个对象组合为一个,并且都分配了已知变量。就我而言,它必须是动态的,因为搜索变量的数量可以变化。
  • 我添加到主对象中的每个对象基本上都具有相同的键“$ and”。 extend()和merge()(合并是Angular 1.4的新增功能,它保留嵌套的对象)函数将仅更新相同的键,除非您传递空的{}对象作为第一个参数。这个最终对象将传递给它的过滤功能需要在上面显示的结构中。

  • 我的代码现在的结果是这样的:
    {
        $and: {
            "attribute_id": 2750,
            "type": "min",
            "display_value": {
                $lte: 17,
                $gte: 2
            }
        }
    }
    

    它似乎是替代而不是附加。我怎样才能将其追加?

    最佳答案

    您当前编写的查询将始终返回false。在没有合并修饰符的情况下,始终假定“和”(根据文档)。因此,您正在寻找attribute_id为2422、2421和2750的对象。

    从逻辑上讲这是不可能的,因此我假设您的意思是以下内容(即使它仍然无效):

    {
        $or: {
            $and: {
                "attribute_id": 2422,
                "type": "max",
                "display_value": {
                    $lte: 200,
                    $gte: 0.3
                }
            },
            $and: {
                "attribute_id": 2421,
                "type": "typ",
                "display_value": {
                    $lte: 150,
                    $gte: 50
                }
            }
            $and: {
                "attribute_id": 2750,
                "type": "min",
                "display_value": {
                    $lte: 17,
                    $gte: 2
                }
            }
        }
    }
    

    事实证明,即使文档从未说明,代码实际上也支持数组:

    var models = [
      { x: 0, y: 0 },
      { x: 0, y: 1 },
      { x: 0, y: 2 },
      { x: 0, y: 3 },
      { x: 1, y: 0 },
      { x: 1, y: 1 },
      { x: 1, y: 2 },
      { x: 1, y: 3 }
    ];
    
    var result = _.query( models, {
        $or: [
          { $and: { x: 0, y: 1 } },
          { $and: { x: 1, y: 0 } }
        ]
    });
    
    console.log( result );
    // result = [ { x: 0, y: 0 }, { x: 1, y: 0 } ]
    <!-- No CDN for underscore-query -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
    <script>(function(){var e,t,r,n,u,a,s,i,o,c,l,f,y,h,p,$,d,g,m,k,v,b,w,O,x,q,j=[].slice,E=[].indexOf||function(e){for(var t=0,r=this.length;r>t;t++)if(t in this&&this[t]===e)return t;return-1},A={}.hasOwnProperty;for($=this,w={},b=function(){var e;return e={},["every","some","filter","reduce","map"].forEach(function(t){return e[t]=function(){var e,r;return r=arguments[0],e=2<=arguments.length?j.call(arguments,1):[],r[t].apply(r,e)}}),e.keys=Object.keys,e.isArray=Array.isArray,e.result=function(e,t){return null==e&&(e={}),"Function"===w.getType(e[t])?e[t]():e[t]},e.detect=function(e,t){var r,n,u;for(n=0,u=e.length;u>n;n++)if(r=e[n],t(r))return r},e.reject=function(e,t){var r,n,u,a;for(a=[],n=0,u=e.length;u>n;n++)r=e[n],t(r)||a.push(r);return a},e.intersection=function(e,t){var r,n,u,a;for(a=[],n=0,u=e.length;u>n;n++)r=e[n],-1!==t.indexOf(r)&&a.push(r);return a},e.isEqual=function(e,t){return JSON.stringify(e)===JSON.stringify(t)},e},n=function(e){var t,r,n,u;for(u=["every","some","filter","detect","reject","reduce","intersection","isEqual","keys","isArray","result","map"],r=0,n=u.length;n>r;r++)if(t=u[r],w[t]=e[t],!w[t])throw new Error(""+t+" missing. Please ensure that you first initialize underscore-query with either lodash or underscore")},w.getType=function(e){var t;return t=Object.prototype.toString.call(e).substr(8),t.substr(0,t.length-1)},w.makeObj=function(e,t){var r;return(r={})[e]=t,r},w.reverseString=function(e){return e.toLowerCase().split("").reverse().join("")},w.compoundKeys=["$and","$not","$or","$nor"],w.makeGetter=function(e){return e=e.split("."),function(t){var r,n,u,a;for(n=t,u=0,a=e.length;a>u;u++)r=e[u],n&&(n=w.result(n,r));return n}},o=function(e,t){var r,n,u;u=[];for(r in t)n=t[r],u.push(w.makeObj(e,w.makeObj(r,n)));return u},l=function(e){var t,r,n,u,a,s;switch(t=w.keys(e)[0],u=e[t],r={key:t},(null!=u?u.$boost:void 0)&&(r.boost=u.$boost,delete u.$boost),-1!==t.indexOf(".")&&(r.getter=w.makeGetter(t)),n=w.getType(u)){case"RegExp":case"Date":r.type="$"+n.toLowerCase(),r.value=u;break;case"Object":if(E.call(w.compoundKeys,t)>=0)r.type=t,r.value=y(u),r.key=null;else if(w.keys(u).length>1)r.type="$and",r.value=y(o(t,u)),r.key=null;else for(a in u)if(A.call(u,a)){if(s=u[a],!v(a,s))throw new Error("Query value ("+s+") doesn't match query type: ("+a+")");switch(r.type=a,a){case"$elemMatch":r.value=m(f(s));break;case"$endsWith":r.value=w.reverseString(s);break;case"$likeI":case"$startsWith":r.value=s.toLowerCase();break;case"$not":case"$nor":case"$or":case"$and":r.value=y(w.makeObj(r.key,s)),r.key=null;break;case"$computed":r=l(w.makeObj(t,s)),r.getter=w.makeGetter(t);break;default:r.value=s}}break;default:r.type="$equal",r.value=u}return"$equal"!==r.type||"Object"!==n&&"Array"!==n||(r.type="$deepEqual"),r},y=function(e){var t,r,n,u,a,s,i;for(n=w.isArray(e)?e:function(){var r;r=[];for(t in e)A.call(e,t)&&(u=e[t],r.push(w.makeObj(t,u)));return r}(),i=[],a=0,s=n.length;s>a;a++)r=n[a],i.push(l(r));return i},v=function(e,t){var r;switch(r=w.getType(t),e){case"$in":case"$nin":case"$all":case"$any":return"Array"===r;case"$size":return"Number"===r;case"$regex":case"$regexp":return"RegExp"===r;case"$like":case"$likeI":return"String"===r;case"$between":case"$mod":return"Array"===r&&2===t.length;case"$cb":return"Function"===r;default:return!0}},k=function(e,t){var r;switch(r=w.getType(t),e){case"$like":case"$likeI":case"$regex":case"$startsWith":case"$endsWith":return"String"===r;case"$contains":case"$all":case"$any":case"$elemMatch":return"Array"===r;case"$size":return"String"===r||"Array"===r;case"$in":case"$nin":return null!=t;default:return!0}},h=function(e,t,r,n,u){switch(e){case"$equal":return w.isArray(r)?E.call(r,t)>=0:r===t;case"$deepEqual":return w.isEqual(r,t);case"$contains":return E.call(r,t)>=0;case"$ne":return r!==t;case"$lt":return t>r;case"$gt":return r>t;case"$lte":return t>=r;case"$gte":return r>=t;case"$between":return t[0]<r&&r<t[1];case"$betweene":return t[0]<=r&&r<=t[1];case"$in":return E.call(t,r)>=0;case"$nin":return E.call(t,r)<0;case"$all":return w.every(t,function(e){return E.call(r,e)>=0});case"$any":return w.some(r,function(e){return E.call(t,e)>=0});case"$size":return r.length===t;case"$exists":case"$has":return null!=r===t;case"$like":return-1!==r.indexOf(t);case"$likeI":return-1!==r.toLowerCase().indexOf(t);case"$startsWith":return 0===r.toLowerCase().indexOf(t);case"$endsWith":return 0===w.reverseString(r).indexOf(t);case"$type":return typeof r===t;case"$regex":case"$regexp":return t.test(r);case"$cb":return t.call(n,r);case"$mod":return r%t[0]===t[1];case"$elemMatch":return d(r,t,null,!0);case"$and":case"$or":case"$nor":case"$not":return p(e,t,u,n);default:return!1}},m=function(e,t,r){var n,u;if("String"===w.getType(t)&&(n=t,t=function(e,t){return e[n](t)}),r){if(1!==e.length)throw new Error("score operations currently don't work on compound queries");if(u=e[0],"$and"!==u.type)throw new Error("score operations only work on $and queries (not "+u.type);return function(e){return e._score=p(u.type,u.parsedQuery,t,e,!0),e}}return function(n){var a,s;for(a=0,s=e.length;s>a;a++)if(u=e[a],!p(u.type,u.parsedQuery,t,n,r))return!1;return!0}},p=function(e,t,r,n,u){var a,s,i,o,c,l,f,y,p,$;for(i=0,c=0,l=1/t.length,y=0,p=t.length;p>y;y++)switch(o=t[y],a=o.getter?o.getter(n,o.key):r?r(n,o.key):n[o.key],f=k(o.type,a),f&&(f=h(o.type,o.value,a,n,r)),f&&(i++,u&&(s=null!=($=o.boost)?$:1,c+=l*s)),e){case"$and":if(!u&&!f)return!1;break;case"$not":if(f)return!1;break;case"$or":if(f)return!0;break;case"$nor":if(f)return!1;break;default:throw new Error("Invalid compound method")}return u?c:"$not"===e?0===i:"$or"!==e},f=function(e){var t,r,n,u,a;if(n=w.keys(e),!n.length)return[];if(t=w.intersection(w.compoundKeys,n),0===t.length)return[{type:"$and",parsedQuery:y(e)}];if(t.length!==n.length){E.call(t,"$and")<0&&(e.$and={},t.unshift("$and"));for(r in e)A.call(e,r)&&(a=e[r],E.call(w.compoundKeys,r)<0&&(e.$and[r]=a,delete e[r]))}return function(){var r,n,a;for(a=[],r=0,n=t.length;n>r;r++)u=t[r],a.push({type:u,parsedQuery:y(e[u])});return a}()},c=function(e){var t;return"String"===w.getType(e)&&(t=e,e=function(e,r){return e[t](r)}),e},e=function(){function e(e,t){this.items=e,this._getter=t,this.theQuery={}}return e.prototype.all=function(e,t){return e&&(this.items=e),e=this.indexes?this.getIndexedItems(this.items):this.items,d(e,this.theQuery,this._getter,t)},e.prototype.chain=function(){return _.chain(this.all.apply(this,arguments))},e.prototype.tester=function(){return i(this.theQuery,this._getter)},e.prototype.first=function(e){return this.all(e,!0)},e.prototype.getter=function(e){return this._getter=e,this},e}(),t=function(e){return function(t,r){var n;return r&&(t=w.makeObj(t,r)),null==(n=this.theQuery)[e]&&(n[e]=[]),this.theQuery[e].push(t),this}},q=w.compoundKeys,O=0,x=q.length;x>O;O++)s=q[O],e.prototype[s.substr(1)]=t(s);return e.prototype.find=e.prototype.query=e.prototype.run=e.prototype.all,r=function(t,r){return new e(t,r)},i=function(e,t){return m(f(e),c(t))},a=function(e,t,r){return d(e,t,r,!0)},d=function(e,t,n,u,a){var s;return arguments.length<2?r.apply(this,arguments):(n&&(n=c(n)),"Function"!==w.getType(t)&&(t=m(f(t),n,a)),(s=a?w.map:u?w.detect:w.filter)(e,t))},g=function(e,t,r){return d(e,t,r,!1,!0)},d.build=r,d.parse=f,d.findOne=d.first=a,d.score=g,d.tester=d.testWith=i,d.getter=d.pluckWith=w.makeGetter,u=function(e,t){return null==t&&(t=!0),e||(e=b(),t=!1),n(e),t&&e.mixin({query:d,q:d}),d},$._?u($._):exports&&("undefined"!=typeof module&&null!==module?module.exports:void 0)?module.exports=u:u}).call(this);</script>


    因此,您实际上可以这样编写查询:
    {
        $or: [
            { $and: {
                "attribute_id": 2422,
                "type": "max",
                "display_value": {
                    $lte: 200,
                    $gte: 0.3
                }
            } },
            { $and: {
                "attribute_id": 2421,
                "type": "typ",
                "display_value": {
                    $lte: 150,
                    $gte: 50
                }
            } },
            { $and: {
                "attribute_id": 2750,
                "type": "min",
                "display_value": {
                    $lte: 17,
                    $gte: 2
                }
            } }
        ]
    }
    

    这会使您的函数更加简单:
    var filterArray = [];
    var filterObject = {};
    for (var key in $scope.mpsfilters) {
        if ($scope.mpsfilters.hasOwnProperty(key)) {
            var keyparts = key.split('_');
            filterArray.push({ $and: {
                "attribute_id": keyparts[0],
                "type": keyparts[1],
                "display_value": {$lte: $scope.mpsfilters[key].range_top, $gte: $scope.mpsfilters[key].range_bottom}
            }});
        }
    }
    
    // look how much easier this is!
    filterObject = { $or: filterArray };
    

    10-08 04:58