Mongo 查询按非重复计数排序
Mongo query to sort by distinct count
我有两个字段 'company' 和 'url'。我想按不同 '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 家公司),然后显示与不同公司相对应的三个 URL(如果不同公司的数量至少为三个)。类似于:
{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"}}
其他公司也是如此
这确实(仍然)最好由多个查询处理,因为 MongoDB 实际上 "still" 还没有真正有效的运算符来执行此操作。
你可以用 MongoDB 3.2 做这样的事情,但是有明显的 "catches":
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" 内容的 all 添加到分组数组中。这有可能超过 16MB 的 BSON 限制。可能不会,但是当您只想要 "three" 内容时添加 "all" 内容仍然有点浪费。
因此,即便如此,在前 10 个结果中分别实际查询 "urls" 可能更实用。
这是 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
}
);
}
)
});
是的,更多的是对数据库的调用,但实际上 只有 10 次,因此不是真正的问题。
真正的 解决方案包含在 SERVER-9377 - Extend $push or $max to allow collecting "top" N values per _id key in $group phase 中。这具有良好的 "In Progress" 状态,因此正在积极进行中。
一旦解决了这个问题,那么单个聚合语句就变得可行了,从那时起您就可以 "limit" 初始 $push
中的结果 "urls" 到三个条目,而不是在事后删除除三个之外的所有内容。
我有两个字段 'company' 和 'url'。我想按不同 '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 家公司),然后显示与不同公司相对应的三个 URL(如果不同公司的数量至少为三个)。类似于:
{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"}}
其他公司也是如此
这确实(仍然)最好由多个查询处理,因为 MongoDB 实际上 "still" 还没有真正有效的运算符来执行此操作。
你可以用 MongoDB 3.2 做这样的事情,但是有明显的 "catches":
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" 内容的 all 添加到分组数组中。这有可能超过 16MB 的 BSON 限制。可能不会,但是当您只想要 "three" 内容时添加 "all" 内容仍然有点浪费。
因此,即便如此,在前 10 个结果中分别实际查询 "urls" 可能更实用。
这是 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
}
);
}
)
});
是的,更多的是对数据库的调用,但实际上 只有 10 次,因此不是真正的问题。
真正的 解决方案包含在 SERVER-9377 - Extend $push or $max to allow collecting "top" N values per _id key in $group phase 中。这具有良好的 "In Progress" 状态,因此正在积极进行中。
一旦解决了这个问题,那么单个聚合语句就变得可行了,从那时起您就可以 "limit" 初始 $push
中的结果 "urls" 到三个条目,而不是在事后删除除三个之外的所有内容。