group

在本页面

Definition

Note

由于group使用 JavaScript,因此它受到许多性能限制。在大多数情况下,aggregation pipeline中的$group运算符提供了一种合适的替代方法,其限制较少。

通过指定的键将集合中的文档分组,并执行简单的聚合功能,例如计算计数和总和。该命令类似于 SQL 中的SELECT <...> GROUP BY语句。该命令返回包含分组记录以及命令元数据的文档。

group命令采用以下原型形式:

{
  group:
   {
     ns: <namespace>,
     key: <key>,
     $reduce: <reduce function>,
     $keyf: <key function>,
     cond: <query>,
     finalize: <finalize function>
   }
}

该命令接受具有以下字段的文档:

Field Type Description
ns string 从中执行分组操作的集合。
key document 要分组的一个或多个字段。返回一个“键对象”用作分组键。
$reduce function 在分组操作期间对文档进行操作的聚合功能。这些函数可以返回总和或计数。该函数采用两个参数:当前文档和该组的汇总结果文档。
initial document 初始化聚合结果文档。
$keyf function 可选的。替代key字段。指定一个函数,该函数创建一个“键对象”用作分组键。使用$keyf而不是key来按计算字段而不是现有文档字段分组。
cond document 可选的。选择标准,以确定要处理集合中的哪些文档。如果省略cond字段,则group处理集合中的所有文档以进行组操作。
finalize function 可选的。在group返回最终值之前运行结果集中每个项目的函数。此功能可以修改结果文档或整体替换结果文档。与也指定功能的$keyf$reduce字段不同,此字段名称是finalize不是 $finalize

对于 Shell,MongoDB 提供了包装器方法db.collection.group()。但是,db.collection.group()方法采用keyf字段和reduce字段,而group命令采用$keyf字段和$reduce字段。

Behavior

限制和限制

group命令不适用于sharded clusters。在sharded environments中使用aggregation frameworkmap-reduce

结果集必须在BSON 文档的最大大小之内。

此外,在 2.2 版中,返回的数组最多可以包含 20,000 个元素;即最多 20,000 个唯一分组。对于导致超过 20,000 个唯一分组的分组操作,请使用mapReduce。以前的版本限制为 10,000 个元素。

在 2.4 之前的版本中,group命令获得了mongod实例的 JavaScript 锁,该锁阻止了所有其他 JavaScript 执行。

mongo Shell JavaScript 函数/属性

map-reduce operationsgroup命令和$where运算符表达式**无法访问mongoShell 程序中可用的某些全局函数或属性,例如db

下列 JavaScript 函数和属性**可用于map-reduce operationsgroup命令和$where运算符表达式:

Available Properties Available Functions
args

MaxKey
MinKey
assert()
BinData()
DBPointer()
DBRef()
doassert()
emit()
gc()
HexData()
hex_md5()
isNumber()
isObject()
ISODate()
isString()
Map()
MD5()
NumberInt()
NumberLong()
ObjectId()
print()
printjson()
printjsononeline()
sleep()
Timestamp()
tojson()
tojsononeline()
tojsonObject()
UUID()
version()

JavaScript in MongoDB

尽管group使用 JavaScript,但是大多数与 MongoDB 的交互都不使用 JavaScript,而是使用idiomatic driver作为交互应用程序的语言。

Examples

以下是db.collection.group()方法的示例。这些示例假定orders集合包含以下原型的文档:

{
  _id: ObjectId("5085a95c8fada716c89d0021"),
  ord_dt: ISODate("2012-07-01T04:00:00Z"),
  ship_dt: ISODate("2012-07-02T04:00:00Z"),
  item:
    {
      sku: "abc123",
      price: 1.99,
      uom: "pcs",
      qty: 25
    }
}

按两个字段分组

以下示例按ord_dtitem.sku字段对ord_dt大于01/01/2012的文档进行分组:

db.runCommand(
   {
     group:
       {
         ns: 'orders',
         key: { ord_dt: 1, 'item.sku': 1 },
         cond: { ord_dt: { $gt: new Date( '01/01/2012' ) } },
         $reduce: function ( curr, result ) { },
         initial: { }
       }
   }
)

结果是一个文档,其中包含retval字段,该字段包含按记录分组; count字段,该字段包含分组的文档总数; keys字段,该字段包含唯一分组的数量(即retval中的元素数量);以及ok字段,其中包含命令状态:

{ "retval" :
      [ { "ord_dt" : ISODate("2012-07-01T04:00:00Z"), "item.sku" : "abc123"},
        { "ord_dt" : ISODate("2012-07-01T04:00:00Z"), "item.sku" : "abc456"},
        { "ord_dt" : ISODate("2012-07-01T04:00:00Z"), "item.sku" : "bcd123"},
        { "ord_dt" : ISODate("2012-07-01T04:00:00Z"), "item.sku" : "efg456"},
        { "ord_dt" : ISODate("2012-06-01T04:00:00Z"), "item.sku" : "abc123"},
        { "ord_dt" : ISODate("2012-06-01T04:00:00Z"), "item.sku" : "efg456"},
        { "ord_dt" : ISODate("2012-06-01T04:00:00Z"), "item.sku" : "ijk123"},
        { "ord_dt" : ISODate("2012-05-01T04:00:00Z"), "item.sku" : "abc123"},
        { "ord_dt" : ISODate("2012-05-01T04:00:00Z"), "item.sku" : "abc456"},
        { "ord_dt" : ISODate("2012-06-08T04:00:00Z"), "item.sku" : "abc123"},
        { "ord_dt" : ISODate("2012-06-08T04:00:00Z"), "item.sku" : "abc456"}
      ],
  "count" : 13,
  "keys" : 11,
  "ok" : 1 }

方法调用类似于 SQL 语句:

SELECT ord_dt, item_sku
FROM orders
WHERE ord_dt > '01/01/2012'
GROUP BY ord_dt, item_sku

计算总和

以下示例通过ord_dtitem.sku字段对ord_dt大于01/01/2012的那些文档进行分组,并为每个分组计算qty字段的总和:

db.runCommand(
   { group:
       {
         ns: 'orders',
         key: { ord_dt: 1, 'item.sku': 1 },
         cond: { ord_dt: { $gt: new Date( '01/01/2012' ) } },
         $reduce: function ( curr, result ) {
                     result.total += curr.item.qty;
                  },
         initial: { total : 0 }
       }
    }
)

返回文档的retval字段是一个文档数组,其中包含 group by 字段和计算出的聚合字段:

{ "retval" :
      [ { "ord_dt" : ISODate("2012-07-01T04:00:00Z"), "item.sku" : "abc123", "total" : 25 },
        { "ord_dt" : ISODate("2012-07-01T04:00:00Z"), "item.sku" : "abc456", "total" : 25 },
        { "ord_dt" : ISODate("2012-07-01T04:00:00Z"), "item.sku" : "bcd123", "total" : 10 },
        { "ord_dt" : ISODate("2012-07-01T04:00:00Z"), "item.sku" : "efg456", "total" : 10 },
        { "ord_dt" : ISODate("2012-06-01T04:00:00Z"), "item.sku" : "abc123", "total" : 25 },
        { "ord_dt" : ISODate("2012-06-01T04:00:00Z"), "item.sku" : "efg456", "total" : 15 },
        { "ord_dt" : ISODate("2012-06-01T04:00:00Z"), "item.sku" : "ijk123", "total" : 20 },
        { "ord_dt" : ISODate("2012-05-01T04:00:00Z"), "item.sku" : "abc123", "total" : 45 },
        { "ord_dt" : ISODate("2012-05-01T04:00:00Z"), "item.sku" : "abc456", "total" : 25 },
        { "ord_dt" : ISODate("2012-06-08T04:00:00Z"), "item.sku" : "abc123", "total" : 25 },
        { "ord_dt" : ISODate("2012-06-08T04:00:00Z"), "item.sku" : "abc456", "total" : 25 }
      ],
  "count" : 13,
  "keys" : 11,
  "ok" : 1 }

方法调用类似于 SQL 语句:

SELECT ord_dt, item_sku, SUM(item_qty) as total
FROM orders
WHERE ord_dt > '01/01/2012'
GROUP BY ord_dt, item_sku

计算总和,计数和平均值

以下示例按计算出的day_of_week字段(大于01/01/2012 ord_dt的那些文档)进行分组,并为每个分组计算qty字段的总和,计数和平均值:

db.runCommand(
   {
     group:
       {
         ns: 'orders',
         $keyf: function(doc) {
                    return { day_of_week: doc.ord_dt.getDay() };
                },
         cond: { ord_dt: { $gt: new Date( '01/01/2012' ) } },
         $reduce: function( curr, result ) {
                      result.total += curr.item.qty;
                      result.count++;
                  },
         initial: { total : 0, count: 0 },
         finalize: function(result) {
                      var weekdays = [
                           "Sunday", "Monday", "Tuesday",
                           "Wednesday", "Thursday",
                           "Friday", "Saturday"
                          ];
                      result.day_of_week = weekdays[result.day_of_week];
                      result.avg = Math.round(result.total / result.count);
                   }
       }
   }
)

返回文档的retval字段是一个文档数组,其中包含 group by 字段和计算出的聚合字段:

{
  "retval" :
      [
        { "day_of_week" : "Sunday", "total" : 70, "count" : 4, "avg" : 18 },
        { "day_of_week" : "Friday", "total" : 110, "count" : 6, "avg" : 18 },
        { "day_of_week" : "Tuesday", "total" : 70, "count" : 3, "avg" : 23 }
      ],
  "count" : 13,
  "keys" : 3,
  "ok" : 1
}
首页