我有一个文档集合(grades
),其中缺少一些键,如下所示:
| 名称名称名称|识别码|吉苏布|点数|
| - -|- -|- -|- -|
| 彼得|一个||一百二十三|
| | 一个|聚丙烯|四百五十六|
| 爱丽斯||爱丽丝1|二百三十四|
| | 2个|爱丽丝1|五六七|
我想通过匹配Name、ID或Github中的任何一个来对这些数据进行分组,并收集点数。结果应该如下所示:
| 识别码(_I)|点数|
| - -|- -|
| [彼得,1,PPane]|[一二三,四五六]|
| [爱丽丝,2,爱丽丝1]|【二三四,五六七】|
现在我在后端这样做:
const students = new Map<string, CourseStudent>();
const keys = ['Name', 'ID', 'Github'];
for (const grade of grades) {
let student: CourseStudent | undefined = undefined;
for (const key of keys) {
const value = grade[key];
if (value && (student = students.get(value))) {
break;
}
}
if (!student) {
const {Name, ID, Github} = grade;
student = {_id: {Name, ID, Github}, points: []};
}
for (const key of keys) {
const value = grade[key];
if (value) {
students.set(value, student);
}
}
student.points.push(grade.points);
}
return Array.from(students.values());
我的用例中的数据大小是1000-10000个年级(100-1000个学生x 10个作业)。实际的“年级”数据包含更多的字段,其中大多数字段不用于最终结果,但将所有这些字段保存在内存中可能会花费很大的成本。
是否有办法在数据库中通过聚合管道(例如使用$group
)实现这一点?
首先,这里是一个非工作聚合,因为它要求所有字段匹配,而不是只有一个:
{$group: {_id: ['$Name', '$ID', '$Github'], points: {$push: '$Points'}}},
1条答案
按热度按时间oalqel3c1#
由于您只有3个密钥可供使用,因此按一个密钥分组并收集另外两个密钥将导致仅缺少一个密钥:
$group
乘以ID
并收集其他密钥。假设每个用户至少有一个文档包含该用户的key
(如您示例中所示),此步骤的结果是文档数等于用户数+ 1。每个文档包含用户ID
和Name
或Github
。一份文件指所有文件,不含任何ID
。$match
仅保留用户文档1.对于每个用户文档,使用
$lookup
获取所有匹配的原始文档,现在我们有了获取它们所需的数据。1.对结果进行分组和格式化。
了解它在playground example上的工作原理