有没有办法投影字段的类型

时间:2014-02-12 02:02:22

标签: mongodb mapreduce mongodb-query aggregation-framework

假设我们有类似下面的文档,但我们只想返回包含数字信息的字段:

{
    "_id" : ObjectId("52fac254f40ff600c10e56d4"),
    "name" : "Mikey",
    "list" : [ 1, 2, 3, 4, 5 ],
    "people" : [ "Fred", "Barney", "Wilma", "Betty" ],
    "status" : false,
    "created" : ISODate("2014-02-12T00:37:40.534Z"),
    "views" : 5
}

现在我知道我们可以使用$type运算符查询匹配特定类型的字段。但我还是偶然发现了将此作为一个字段值的方法。因此,如果我们以“展开”的形式查看文档,您会看到:

{
    "_id" : ObjectId("52fac254f40ff600c10e56d4"),
    "name" : 2,
    "list" : 16,
    "people" : 2
    "status" : 8,
    "created" : 9,
    "views" : 16
}

最终目标是仅列出匹配某种类型的字段,假设比较得到数字类型并过滤掉字段,经过多次文档修改后,产生如下结果:

{
    "_id" : ObjectId("52fac254f40ff600c10e56d4"),
    "list" : [ 1, 2, 3, 4, 5 ],
    "views" : 5
}

有没有人有办法解决这个问题。

1 个答案:

答案 0 :(得分:2)

有一些问题使得这不切实际:

  1. 由于查询是与投影能力相关的一个独特参数,因此单独一个查询无法做到这一点,因为投影不会受到查询结果的影响
  2. 由于聚合框架没有办法迭代字段并检查类型,这也不是一个选项
  3. 话虽如此,有一种使用Map-Reduce的方式有点令人讨厌的方法可以得到类似的答案,尽管Map-Reduce样式输出并不令人敬畏:

    map = function() {
        function isNumber(n) {
          return !isNaN(parseFloat(n)) && isFinite(n);
        }
    
        var numerics = [];
        for(var fn in this) {
            if (isNumber(this[fn])) {
                numerics.push({f: fn, v: this[fn]});
            }
            if (Array.isArray(this[fn])) {
                // example ... more complex logic needed
                if(isNumber(this[fn][0])) {
                    numerics.push({f: fn, v: this[fn]});
                }
            }
        }
        emit(this._id, { n: numerics });
    };
    
    reduce = function(key, values) {
      return values;  
    };
    

    它不完整,但结果与您想要的结果类似:

    "_id" : ObjectId("52fac254f40ff600c10e56d4"),
     "value" : {
             "n" : [
                     {
                             "f" : "list",
                             "v" : [
                                     1,
                                     2,
                                     3,
                                     4,
                                     5
                             ]
                     },
                     {
                             "f" : "views",
                             "v" : 5
                     }
             ]
     }
    

    地图只是查看每个属性并确定它是否看起来像一个数字......如果是这样,添加到将存储为对象的数组,以便map-reduce引擎不会阻塞数组输出。我在示例代码中保持简单 - 您可以确保数字和数组检查的逻辑。 :)

    当然,它不像find或聚合一样存在,但由于MongoDB的设计并未考虑到这一点,如果你真的想要这个功能,可能需要这样做。