我有两个字段'company'和'url'。我想按照不同的“公司”发生次数对其进行排序,然后显示与该特定公司相对应的三个“网址”。数据存储如下:
{
"_id" : ObjectId("56c4f73664af6f7305f3670f"),
"title" : "Full Stack Software Developer",
"url" : "http://www.indeed.com/cmp/Upside-Commerce,-Inc./jobs/Full-Stack-Software-Developer-6e93e36ea5d0e57e?sjdu=QwrRXKrqZ3CNX5W-O9jEvRQls7y2xdBHzhqWkvhd5FFfs8wS9wesfMWXjNNFaUXen2pO-kyc_Qbr7-_3Gf40AvyEQT3jn6IRxIwvw9-aFy8",
"company" : "Upside Commerce, Inc."
}
以下查询计算不同公司的数量。
db.Books.aggregate({$group : { _id : '$company', count : {$sum : 1}}})
以下是输出:
{ "_id" : "Microsoft", "count" : 14 }
{ "_id" : "Tableau", "count" : 64 }
{ "_id" : "Amazon", "count" : 64 }
{ "_id" : "Dropbox", "count" : 64 }
{ "_id" : "Amazon Corporate LLC", "count" : 64 }
{ "_id" : "Electronic Arts", "count" : 64 }
{ "_id" : "CDK Global", "count" : 65 }
{ "_id" : "IDC Technologies", "count" : 64 }
{ "_id" : "Concur", "count" : 64 }
{ "_id" : "Microsoft", "count" : 14 }
{ "_id" : "Tableau", "count" : 64 }
{ "_id" : "Amazon", "count" : 64 }
{ "_id" : "Dropbox", "count" : 64 }
{ "_id" : "Amazon Corporate LLC", "count" : 64 }
{ "_id" : "Electronic Arts", "count" : 64 }
{ "_id" : "CDK Global", "count" : 65 }
{ "_id" : "IDC Technologies", "count" : 64 }
{ "_id" : "Concur", "count" : 64 }
然而,我希望它按不同公司的数量排序(将其限制为前10名最高的公司),然后显示对应于不同公司的三个网址(如果不同公司的计数至少为三)。类似的东西:
{for microsoft:
{"url" : "https://careers.microsoft.com/jobdetails.aspx?jid=216571&memid=1071484607&utm_source=Indeed"}
{"url" : "https://careers.microsoft.com/jobdetails.aspx?jid=216571&memid=1695844082&utm_source=Indeed" }
{ "url" : "https://careers.microsoft.com/jobdetails.aspx?jid=216571&memid=932148152&utm_source=Indeed"}}
其他公司也一样
答案 0 :(得分:2)
这真的(仍)最好由多个查询处理,因为MongoDB真的"仍然"没有真正有效的运营商来做这件事。
你可以用MongoDB 3.2做这样的事情,但有明显的"捕获":
db.Books.aggregate([
{ "$group": {
"_id": "$company",
"count": { "$sum": 1 },
"urls": {
"$push": "$url"
}
}},
{ "$sort": { "count": -1 } },
{ "$limit": 10 },
{ "$project": {
"count": 1,
"urls": { "$slice": ["$urls",0, 3] }
}}
])
显而易见的问题是,无论如何,你仍然在添加所有的" url"内容到分组数组中。这有可能超过16MB的BSON限制。它可能没有,但是添加"所有"它仍然有点浪费。当你只想要"三"他们。
所以即便如此,实际查询" urls"可能更实际。单独列出前10名结果中的每一项。
这里是node.js的列表,演示了:
var async = require('async'),
mongodb = require('mongodb'),
MongoClient = mongodb.MongoClient;
MongoClient.connect("mongodb://localhost/test",function(err,db) {
if (err) throw err;
// Get the top 10
db.collection("Books").aggregate(
[
{ "$group": {
"_id": "$company",
"count": { "$sum": 1 }
}},
{ "$sort": { "count": -1 } },
{ "$limit": 10 }
],function(err,results) {
if (err) throw err;
// Query for each result and map query response as urls
async.map(
results,
function(result,callback) {
db.collection("Books").find({
"company": result.company
}).limit(3).toArray(function(err,items) {
result.urls = items.map(function(item) {
return item.url;
});
callback(err,result);
})
},
function(err,results) {
if (err) throw err;
// each result entry has 3 urls
}
);
}
)
});
是的,它对数据库的更多调用,但实际上只有十个,因此不是真正的问题。
真实的解决方案包含在SERVER-9377 - Extend $push or $max to allow collecting "top" N values per _id key in $group phase中。这有希望的"进展中"状态,因此它正在积极开展工作。
一旦解决了这个问题,那么单个聚合语句就变得可行了,从那以后你就可以“限制”#34;由此产生的"网址"在初始$push
只有三个条目,而不是在事后删除除了三个以外的所有条目。