计算一个字段在一个集合中出现的次数,同时保留所有没有重复的数据

比方说,我有这样一个集合:

{ _id : 544e97123c9ef694fc68e21b, title: "First Title", notebook: { title: "Misc", slug: "misc" } } { _id: 54ab035a849788d0921d8eb2, title: "Second Title", notebook: { title: "Personal", slug: "personal" } } { _id: 544e97123c9ef694fc68e21b, title: "Third Title", notebook: { title: "Misc", slug: "misc" } } 

在我看来,我希望能够显示一个笔记本标题已经被使用了多less次,以及与特定笔记本的slu link连接,没有特定的顺序。 例如:

 <a href="/notebooks/misc">Misc(2)</a> <a href="/notebooks/personal">Personal(1)</a> 

我通过浏览每个文档来达到这个目的,但问题在于它是因为它正在经历每个文档而重复的。 所以我认为它看起来像这样:

 <a href="/notebooks/misc">Misc(2)</a> <a href="/notebooks/personal">Personal(1)</a> <a href="/notebooks/misc">Misc(2)</a> 

我怎样才能抓住notebook.title,notebook.slug,算他们,没有重复?

这是我目前这样做(这导致重复)hacky的方式:

 function countNotebooks(notes) { var table = Object.create(null); for (var i = 0; i < notes.length; i++) { if (typeof table[notes[i].notebook.slug] === 'undefined') { table[notes[i].notebook.slug] = 1; } else { table[notes[i].notebook.slug] += 1; } } return table; } app.get('/notebooks', function(req, res) { Note.find(function(err, notes) { if (err) { throw err; } res.render('notebooks/index.html', { title: 'All Notebooks', jumbotron: 'Notebooks', notes: notes, notesTable: countNotebooks(notes) }); }); }); 

笔记本电脑/ index.html的:

 {% for note in notes %} <article class="note"> <h3 class="note-title"> <a href="/notebooks/{{ note.notebook.slug }}">{{ note.notebook.title }}</a> <span class="count">({{ notesTable[note.notebook.slug] }})</span> </h3> </article> {% endfor %} 

您可以通过基于共同密钥对数据进行分组来完成此操作。 MongoDB的聚合框架是为这种聚合和操纵而devise的。

首先,我可以改正你的数据样本,因为你有一个重复的_id值,这是不允许的。

 { "_id" : ObjectId("544e97123c9ef694fc68e21b"), "title" : "First Title", "notebook" : { "title" : "Misc", "slug" : "misc" } }, { "_id" : ObjectId("54ab035a849788d0921d8eb2"), "title" : "Second Title", "notebook" : { "title" : "Personal", "slug" : "personal" } }, { "_id" : ObjectId("54ac074fa8a621d3fd49ac91"), "title" : "Third Title", "notebook" : { "title" : "Misc", "slug" : "misc" } } 

要为数据中的“slug”发生添加“计数”值,您可以形成如下的pipe道:

 Note.aggregate([ // Group on the slug values and put other fields in an array { "$group": { "_id": "$notebook.slug", "count": { "$sum": 1 }, "docs": { "$push": { "_id": "$_id", "title": "$title", "notebook": "$notebook" } } }}, // Unwind the created array elements { "$unwind": "$docs" }, // Re-structure back to original form { "$project": { "_id": "$docs._id", "title": "$docs.title", "count": "$count", "notebook": "$docs.notebook" }}, // Sort in original order (or as desired) { "$sort": { "_id": 1 } } ],function(err,result) { }); 

那会给你什么结果是这样的:

 { "_id" : ObjectId("544e97123c9ef694fc68e21b"), "count" : 2, "title" : "First Title", "notebook" : { "title" : "Misc", "slug" : "misc" } }, { "_id" : ObjectId("54ab035a849788d0921d8eb2"), "count" : 1, "title" : "Second Title", "notebook" : { "title" : "Personal", "slug" : "personal" } }, { "_id" : ObjectId("54ac074fa8a621d3fd49ac91"), "count" : 2, "title" : "Third Title", "notebook" : { "title" : "Misc", "slug" : "misc" } } 

那就是如果你想“保留文档”,但是如果你只想要像“facet count”这样独特的“slug”,那么只需在笔记本标题上使用$first ,而不是$push与其他内容:

 Note.aggregate([ // Group on the slug values and put other fields in an array { "$group": { "_id": "$notebook.slug", "count": { "$sum": 1 }, "title": { "$first": "$notebook.title" } }}, ],function(err,result) { }); 

这应该是相当自我解释,但只是总结。 最初的$group是使用“slug”的值来完成的,使用$sum运算符来计算出现次数。 为了保留文档数据的其余部分,使用$push其放置在“slug”下的数组中。

分组后,使用$unwind将数组解规格化为文档,然后使用$project简单地重新构造回原始forms。 最后的$sort操作提供了原始的顺序或任何你想要的,因为sorting在$grouppipe道阶段被改变了。

这不仅可以得到结果,而且可以让您使用带有计数值的$limit$skip操作符来“页面化”数据,甚至根据需要对这些计数值进行sorting。

看看完整的ggregationpipe道运算符参考了解完整的描述和其他可以在这里完成的事情。

你需要:

  • 通过notebook.slugnotebook.title字段Group ,以消除重复。
  • 由于显示顺序并不重要,因此您可以在此跳过sort阶段。
  • Project他们。

码:

 Model.aggregate([ {$group:{"_id":{"title":"$notebook.title", "slug":"$notebook.slug"}, "count":{$sum:1}}}, {$project:{"title":"$_id.title", "slug":"$_id.slug", "count":1,"_id":0}} ],function(err,data){ // handle response and store it in the `notes` variable to be // used to display. }) 

O / P:

 { "count" : 1, "title" : "Personal", "slug" : "personal" } { "count" : 2, "title" : "Misc", "slug" : "misc" } 

并显示为,

 {% for note in notes %} <article class="note"> <h3 class="note-title"> <a href="/notebooks/{{ note.slug }}">{{ note.title }}</a> <span class="count">({{note.count}})</span> </h3> </article> {% endfor %}