MongoDB属性字符串以查询和设置组ID开始

时间:2017-10-16 12:31:28

标签: mongodb mongodb-query aggregation-framework

大集合中的数据结构 - 一个文档

{
  OPERATINGSYSTEM: "Android 6.0"
}

问题:操作系统可以等于例如" Android 5.0"," Android 6.0"," Windows Phone"," Windows Phone 8.1"

没有属性只包含操作系统的类型,例如只有Android

我需要获得Windows手机和Android手机的数量。

我的临时解决方案:

db.getCollection('RB').find(
    {OPERATINGSYSTEM: {$regex: "^Android"}}
).count();

我正在通过Windows Phone等取代"^Android"进行查询,这需要花费很多时间并且需要并行完成。

使用聚合框架我虽然这个:

db.RB.aggregate(
{$group: {_id: {OPERATINGSYSTEM:"$OPERATINGSYSTEM"}}},)

但是使用这个我得到每个操作系统版本Android 5.0Android 6.0等的条目......

我正在搜索的解决方案应该以这种格式返回数据:

{
  "Android": 50,
  "Windows Phone": 100
}

如何在单个查询中完成此操作?

2 个答案:

答案 0 :(得分:2)

如果你的字符串至少一致地将数字版本作为字符串中的最后一个东西,那么你可以使用$split和聚合框架从"空格分隔" content,然后在重建之前从数组中删除最后一个元素:

给出如下数据:

{ "name" : "Android 6.0" }
{ "name" : "Android 7.0" }
{ "name" : "Windows Phone 10"  }

您可以尝试:

db.getCollection('phones').aggregate([
  { "$group": {
    "_id": {
      "$let": {
        "vars": { "split": { "$split": [ "$name", " " ] } },
        "in": {
          "$reduce": {
            "input": { "$slice": [ "$$split", 0, { "$subtract": [ { "$size": "$$split" }, 1 ] } ] },
            "initialValue": "",
            "in": {
              "$cond": {
                "if": { "$eq": [ "$$value", "" ] },
                "then": "$$this",
                "else": { "$concat": [ "$$value", " ", "$$this" ] }   
              }
            }
          }
        } 
      }
    },
    "count": { "$sum": 1 }
  }},
  { "$replaceRoot": {
    "newRoot": {
      "$arrayToObject": [[{ "k": "$_id", "v": "$count" }]]
    }  
  }}
])

如果您的MongoDB至少是MongoDB 3.4以支持$split$reduce,那么这一切都是可能的。 $replaceRoot实际上是关于命名键,而不是真正需要的。

或者,您可以使用mapReduce

db.getCollection('phones').mapReduce(
  function() {
    var re = /\d+/g;
    emit(this.name.substr(0,this.name.search(re)-1),1);
  },
  function(key,values) { return Array.sum(values) },
  { "out": { "inline": 1 } } 
)

通过发生数值的索引更容易分解字符串。在任何一种情况下,您都不需要"硬编码"任何东西,键的值完全取决于上下文中的字符串。

请记住,除非存在极大数量的可能值,否则运行并行.count()操作"应该"是最快的处理,因为返回光标计数比实际计算聚合条目快得多。

答案 1 :(得分:0)

您可以使用map reduce,并在地图功能中应用您的逻辑。

var map  = function(){
    var name = this.op.includes("android") ? "Android" : ""; // could be a regexp

    if(name === ""){
        name = this.op.includes("windows") ? "Windows" : "";
    }

    emit(name, 1);
}

var reduce = function(key, values){
    return Array.sum(values)
}

db.operating.mapReduce(map, reduce, {out: "total"})

https://docs.mongodb.com/manual/tutorial/map-reduce-examples/