翻译或纠错本页面

对用户爱好数据做聚合

数据模型

假定某个运动俱乐部使用了名为 users 的集合,存储了用户入会时间,喜欢的运动等数据,在文档中的格式如下:

{
  _id : "jane",
  joined : ISODate("2011-03-02"),
  likes : ["golf", "racquetball"]
}
{
  _id : "joe",
  joined : ISODate("2012-07-02"),
  likes : ["tennis", "golf", "swimming"]
}

将文档标准化后再排序

下面的操作返回按字母顺序排序的大写格式的用户名称记录。该聚合包含了 users 集合中所有文档的用户名。你可能需要预先把用户名标准化,以方便后面步骤的处理。

db.users.aggregate(
  [
    { $project : { name:{$toUpper:"$_id"} , _id:0 } },
    { $sort : { name : 1 } }
  ]
)

users 集合中的所有文档都输入到管道,该管道包含了以下的操作:

  • 执行 $project 操作:

    • 创建新的字段 name

    • 首先使用 $toUpper 操作符将 _id 的值转换为大写格式,并把新值保存在由 $project 创建的新的字段 name 中。

    • 删除 id 字段。除非明确删除 _id 字段,否则 $project 会默认保留该字段。

  • 使用 $sort 操作符对结果集按 name 字段进行排序。

本次聚合的结果如下:

{
  "name" : "JANE"
},
{
  "name" : "JILL"
},
{
  "name" : "JOE"
}

查询按入会日期排序的用户名列表

接下来的聚合操作将会返回按入会日期排序的用户名列表。这样的聚合可以帮助生成会员的续费通知。

db.users.aggregate(
  [
    { $project :
       {
         month_joined : { $month : "$joined" },
         name : "$_id",
         _id : 0
       }
    },
    { $sort : { month_joined : 1 } }
  ]
)

管道会查询 users 集合中的所有文档,并进行下面这些操作的处理。

  • 执行 $project 操作:

    • 创建两个新的字段: month_joinedname

    • 从结果集中删除 id 字段。除非明确删除 id 字段,否则 aggregate() 方法默认保留该字段。

  • $month 操作符从 joined 字段读取到用户的入会月份,并使用 $project 把入会月份赋值到 month_joined 字段。

  • 使用 $sort 操作符对结果集按 month_joined 字段进行排序。

该操作返回的结果集是这样的:

{
  "month_joined" : 1,
  "name" : "ruth"
},
{
  "month_joined" : 1,
  "name" : "harold"
},
{
  "month_joined" : 1,
  "name" : "kate"
}
{
  "month_joined" : 2,
  "name" : "jill"
}

计算每个月的入会人数

下面的操作计算每个月份的入会人数。你可以使用这些数据来制定营销策略和展开会员续费活动。

db.users.aggregate(
  [
    { $project : { month_joined : { $month : "$joined" } } } ,
    { $group : { _id : {month_joined:"$month_joined"} , number : { $sum : 1 } } },
    { $sort : { "_id.month_joined" : 1 } }
  ]
)

管道会查询 users 集合中的所有文档,并进行下面这些操作的处理。

  • 使用 $project 创建一个新的字段 month_joined

  • $month 操作符从 joined 字段读取到用户的入会月份,并使用 $project 把入会月份赋值到 month_joined 字段。

  • $group 遍历所有文档,并计算每个月份的入会人数。 $group 会为每个月份创建一个新的包含两个字段的新文档:

    • _id,包含了一个内嵌文档,文档里面记录了 month_joined 字段和它的值。

    • 新加的 number 字段。 $sum 会统计所有当前月份入会的人数,并保存在 number 中。

  • $sort 会为新创建的文档按 month_joined 字段进行排序。

本次聚合操作的结果是:

{
  "_id" : {
    "month_joined" : 1
  },
  "number" : 3
},
{
  "_id" : {
    "month_joined" : 2
  },
  "number" : 9
},
{
  "_id" : {
    "month_joined" : 3
  },
  "number" : 5
}

查找最受会员喜欢的5种运动

下面的操作计算最受会员喜欢的5种运动。这样的分析可以帮助制定未来的发展计划。

db.users.aggregate(
  [
    { $unwind : "$likes" },
    { $group : { _id : "$likes" , number : { $sum : 1 } } },
    { $sort : { number : -1 } },
    { $limit : 5 }
  ]
)

本次管道首先读取 users 中的所有文档,并对这些文档进行下面的操作:

  • $unwind 首先对 likes 数组中的值进行分类,并为数组的每个值创建一个新的文档。

    例子

    users 集合中有一些这样的文档

    {
      _id : "jane",
      joined : ISODate("2011-03-02"),
      likes : ["golf", "racquetball"]
    }
    

    $unwind 会创建出下面的文档:

    {
      _id : "jane",
      joined : ISODate("2011-03-02"),
      likes : "golf"
    }
    {
      _id : "jane",
      joined : ISODate("2011-03-02"),
      likes : "racquetball"
    }
    
  • $group 计算每种 likes 的总数。在这个步骤中, $group 会一个创建新的文档:

    • _id,记录了 likes 值。

    • number,保存了由 $sum 统计的每种 likes 的总人数值。

  • $sort 对这些文档按 number 字段进行降序排序。

  • $limit 限定最前面的5个结果。

The results of aggregation would resemble the following:

{
  "_id" : "golf",
  "number" : 33
},
{
  "_id" : "racquetball",
  "number" : 31
},
{
  "_id" : "swimming",
  "number" : 24
},
{
  "_id" : "handball",
  "number" : 19
},
{
  "_id" : "tennis",
  "number" : 18
}