MongoDB按数组内元素分组

59

我有一份文章清单,每篇文章都有一个数组属性,列出了其中提到的各种个人:

_id: {
    $oid: "52b632a9e4f2ba13c82ccd23"
},
providerName: "The Guardian",
url: "http://feeds.theguardian.com/c/34708/f/663860/s/3516cebc/sc/38/l/0L0Stheguardian0N0Cmusic0C20A130Cdec0C220Cwaterboys0Efishermans0Eblues0Etour0Ehammersmith/story01.htm",
subject: "The Waterboys – review",
class_artist: [
    "paul mccartney"
]

我一直在尝试(但不成功)获取过去7天内被标记的所有个别艺术家(class_artist),基于他们被标记文章数目的列表。

我现在已经做到了:

var date = new Date();
date.setDate(date.getDate() - 7);

db.articles.group({
    key: { class_artist: 1 },
    cond: { class_date: { $gt: date } },
    reduce: function ( curr, result ) { result.cnt++; },
    initial: { cnt : 0 }
}).sort({cnt: -1});

不幸的是,它不是基于单个数组值进行计数,而是基于数组构成(即艺术家列表)进行计数。

我尝试使用$unwind函数,但未能使其正常工作。

1个回答

165

你在使用什么框架?这不是MongoDB shell,看起来像一些奇怪的封装,围绕MapReduce。在这种情况下,$unwind将不可用,而你需要它来在聚合框架中使用。以下是在Mongo shell中所需的内容:

db.articles.aggregate([
  {$match: { class_date: { $gte: date } } },
  {$project: { _id: 0, class_artist: 1 } },
  {$unwind: "$class_artist" },
  {$group: { _id: "$class_artist", tags: { $sum: 1 } }},
  {$project: { _id: 0,class_artist: "$_id", tags: 1 } },
  {$sort: { tags: -1 } }
])

如此高效:

  1. 根据日期筛选,因为您已经设置了最近7天的变量
  2. 仅投射我们需要的字段(我们只需要一个!)
  3. 展开数组,这样我们现在就可以得到每个文档中每个数组元素的记录
  4. 按照扩展文档中的艺术家进行分组
  5. 将结果投射成文档格式,您可以将其用作组合_id
  6. 按相反顺序排序以查看首先标记的前几个

聚合的好处在于您可以逐步构建这些阶段,以了解正在发生的情况。

根据需要将其摇身一变成为您自己的驱动程序实现或ODM框架。


4
FYI,"奇怪的装饰器"格式是JavaScript实现的group()命令,早于聚合框架。请参阅:MongoDB聚合比较:group(),$group和MapReduce - Stennie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接