MongoDB Aggregate 4 例

有数据格式如下:

{
"id": "745",
"knownName": {
"en": "A. Michael Spence",
"se": "A. Michael Spence"
},
"familyName": {
// 结构同上,下同
// ..
},
"orgName": {
// orgName 当获奖者为组织时出现
// ..
},
"gender": "male",
"nobelPrizes": [
{
"awardYear": "2001",
// ...
"affiliations": [
{
"name": {
"en": "Stanford University",
// ...
},
"city": {
// ...
},
"country": {
// ...
},
// ...
}
]
}
]
}

想要实现:

  1. 查找名为 CERNaffiliation 的所在国家
  2. 查找获奖次数大于等于 5 次的 familyName
  3. 查找 University of California 的不同所在位置总数
  4. 查找至少一个诺贝尔奖授予组织而非个人的年份总数

查找名为 CERN 的 affiliation 的所在国家

需要注意的是 affiliationsnobelPrizes 下的数组(嵌套数组结构),因此需要分两次展开:

db.laureates.aggregate(
[
// 展开 nobelPrizes
{ $unwind: '$nobelPrizes' },
// 展开 nobelPrizes 下面的 affiliations
{ $unwind: '$nobelPrizes.affiliations' },
// 找到名为 CERN 的记录
{ $match: { 'nobelPrizes.affiliations.name.en': 'CERN' } },
// 将结果限制为 1 条
{ $limit: 1 },
// 映射输出
{ $project: { '_id': 0, 'country': '$nobelPrizes.affiliations.country.en' } }
]
);

// output:
// { "country" : "Switzerland" }

查找获奖次数大于等于 5 次的 familyName

这里需要用到 $group 操作,根据 familyName 来进行分组,并且需要提前计算好每条记录所获奖的数量:

db.laureates.aggregate(
[
// 映射每条记录的 nobelPrizes 长度为 nobelPrizesLength,familyName.en 为 familyName
{ $project: { nobelPrizesLength: { $size: "$nobelPrizes" }, familyName: "$familyName.en" } },
// 找到 familyName 存在的记录(非组织获奖)
{ $match: { familyName: { $exists: !0, $ne: null } } },
// 以 familyName 为依据进行分组,并累加 nobelPrizesLength 作为 count
{ $group: { _id: "$familyName", count: { $sum: "$nobelPrizesLength" }, familyName: { $first: "$familyName" } } },
// 找到 count 大于等于 5 的记录
{ $match: { count: { $gte: 5 } } },
// 映射输出
{ $project: { familyName: "$familyName", _id: 0 } }
]
);

// output:
// { "familyName" : "Smith" }
// { "familyName" : "Wilson" }

查找 University of California 的不同所在位置总数

一个相比上个查询更简单的 group 查询:

db.laureates.aggregate(
[
// 展开 nobelPrizes
{ $unwind: "$nobelPrizes" },
// 展开 nobelPrizes 下面的 affiliations
{ $unwind: "$nobelPrizes.affiliations" },
// 找到名为 University of California 的记录
{ $match: { "nobelPrizes.affiliations.name.en": "University of California" } },
// 以 city 名作为依据分组
{ $group: { _id: "$nobelPrizes.affiliations.city.en" } },
// 输出分组后的总记录数
{ $count: "locations" }
]
);

// output:
// { "locations" : 6 }

查找至少一个诺贝尔奖授予组织而非个人的年份总数

这里注意 group 之前先把授予个人的记录筛除掉:

db.laureates.aggregate(
[
// 找到 orgName 存在的记录(组织获奖)
{ $match: { orgName: { $exists: !0, $ne: null } } },
// 展开 nobelPrizes
{ $unwind: "$nobelPrizes" },
// 以获奖年份分组
{ $group: { _id: "$nobelPrizes.awardYear" } },
// 输出分组后的总记录数
{ $count: "years" }
]
);

// output:
// { "years" : 26 }