我有一个看起来像这样的 mongoDB 集合:
[{
"_id": 1,
"name": "John Doe",
"company": "Acme",
"email": "john.doe@acme.com",
"matches": [171844, 169729, 173168, 174310, 168752, 174972, 172959, 169546]
}, {
"_id": 2,
"name": "Bruce Wayne",
"company": "Wayne Enterprises",
"email": "bruce@wayne.com",
"matches": [171844, 232333, 233312, 123456]
}, {
"_id": 3,
"name": "Tony Stark",
"company": "Stark Industries",
"email": "tony@stark.com",
"matches": [173844, 155729, 133168, 199310, 132752, 139972]
}, {
"_id": 4,
"name": "Clark Kent",
"company": "Daily Planet",
"email": "clark.kent@planet.com",
"matches": [169729, 174310, 168752]
}, {
"_id": 5,
"name": "Lois Lane",
"company": "Daily Planet",
"email": "lois.lane@planet.com",
"matches": [172959, 169546]
}]
Run Code Online (Sandbox Code Playgroud)
我需要得到一个过滤的用户列表,但有一个键,它根据用户拥有的“匹配”记录的数量显示用户的“排名”位置。应该有一个“全球排名”的位置和一个“公司排名”的位置。
所需的结果应该是这样的(例如过滤 company='Daily Planet'):
[ { _id: 4,
name: 'Clark Kent',
company: 'Daily Planet',
email: 'clark.kent@planet.com',
points: 3,
globalRank: 4,
companyRank: 1
},
{ _id: 5,
name: 'Lois Lane',
company: 'Daily Planet',
email: 'lois.lane@planet.com',
points: 2,
globalRank: 4,
companyRank: 2
} ]
Run Code Online (Sandbox Code Playgroud)
请注意,克拉克·肯特在全球排名中排名第 4,因为他有 3 场比赛(约翰·多伊、布鲁斯·韦恩和托尼·斯塔克的比赛比他多)并且在公司排名中排名第一,因为他的比赛比任何 Daily Planet 用户都多.
然而,即使经过几天的研究,我也找不到办法做到这一点。(我什至不知道如何只做全球排名或公司排名)。
我正在使用以下聚合管道,如下所示:
[{
$match: {
company: "Daily Planet"
}
}, {
$project: {
_id: 1,
name: "$name",
company: "$company",
email: "$email",
points: {
$size: "$matches"
}
}
}, {
$sort: {
points: -1
}
}]
Run Code Online (Sandbox Code Playgroud)
但这不会返回排名,只会返回按积分排序的记录。
关于如何解决这个问题,或者如何以不同的方式解决问题的任何想法?
基本思想是首先根据points您所做的对点进行排序,然后将$push它们放入一个数组中。这确保元素按排序顺序插入。然后我们使用该属性$unwindincludeArrayIndex来生成排序数组中与排名相对应的元素的索引。
使用上述逻辑的管道如下(尝试逐步了解以更好地理解):-
aggregate([
{
$project: {
_id: 1,
name: "$name",
company: "$company",
email: "$email",
points: {
$size: "$matches"
}
}
}, {
$sort: {
points: -1
}
},
{
$group: {
_id: {},
arr: {
$push: {
name: '$name',
company: '$company',
email: '$email',
points: '$points'
}
}
}
}, {
$unwind: {
path: '$arr',
includeArrayIndex: 'globalRank',
}
}, {
$sort: {
'arr.company': 1,
'arr.points': -1
}
}, {
$group: {
_id: '$arr.company',
arr: {
$push: {
name: '$arr.name',
company: '$arr.company',
email: '$arr.email',
points: '$arr.points',
globalRank: '$globalRank'
}
}
}
}, {
$unwind: {
path: '$arr',
includeArrayIndex: 'companyRank',
}
}, {
$project: {
_id: 0,
name: '$arr.name',
company: '$arr.company',
email: '$arr.email',
points: '$arr.points',
globalRank: '$arr.globalRank',
companyRank: '$companyRank'
}
}
]);
Run Code Online (Sandbox Code Playgroud)
查询的输出是
/* 1 */
{
"companyRank" : NumberLong(0),
"name" : "Bruce Wayne",
"company" : "Wayne Enterprises",
"email" : "bruce@wayne.com",
"points" : 4,
"globalRank" : NumberLong(2)
}
/* 2 */
{
"companyRank" : NumberLong(0),
"name" : "Tony Stark",
"company" : "Stark Industries",
"email" : "tony@stark.com",
"points" : 6,
"globalRank" : NumberLong(1)
}
/* 3 */
{
"companyRank" : NumberLong(0),
"name" : "Clark Kent",
"company" : "Daily Planet",
"email" : "clark.kent@planet.com",
"points" : 3,
"globalRank" : NumberLong(3)
}
/* 4 */
{
"companyRank" : NumberLong(1),
"name" : "Lois Lane",
"company" : "Daily Planet",
"email" : "lois.lane@planet.com",
"points" : 2,
"globalRank" : NumberLong(4)
}
/* 5 */
{
"companyRank" : NumberLong(0),
"name" : "John Doe",
"company" : "Acme",
"email" : "john.doe@acme.com",
"points" : 8,
"globalRank" : NumberLong(0)
}
Run Code Online (Sandbox Code Playgroud)
此处的排名为 0。
| 归档时间: |
|
| 查看次数: |
4183 次 |
| 最近记录: |