NestJS中使用Mongoose聚合按数组字段分组处理MongoDB数据
实现方案
方法一:MongoDB聚合查询(推荐)
直接通过MongoDB聚合管道在数据库层面完成数据转换,性能更优,适合大数据量场景。在NestJS的Service中可以这样实现:
import { Injectable } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { Model } from 'mongoose'; import { YourDocument, YourModelName } from './schemas/your.schema'; // 替换为你的模型类型 @Injectable() export class YourService { constructor( @InjectModel(YourModelName) private readonly yourModel: Model<YourDocument>, ) {} async findByIdWithGroupedRooms(id: string) { const result = await this.yourModel.aggregate([ // 匹配目标文档 { $match: { _id: this.yourModel.Types.ObjectId(id) } }, // 展开rooms数组,将每个元素转为独立文档 { $unwind: '$rooms' }, // 按根文档字段+rooms.name分组,收集对应的workId { $group: { _id: { _id: '$_id', organization: '$organization', name: '$rooms.name', }, workIds: { $push: '$rooms.workId' }, }, }, // 调整字段结构,拆分嵌套字段 { $project: { _id: '$_id._id', organization: '$_id.organization', name: '$_id.name', workIds: 1, }, }, // 重新按根文档字段分组,组装新的rooms数组 { $group: { _id: { _id: '$_id', organization: '$organization' }, rooms: { $push: { name: '$name', workIds: '$workIds' } }, }, }, // 替换根文档,生成最终输出格式 { $replaceRoot: { newRoot: { _id: '$_id._id', organization: '$_id.organization', rooms: '$rooms', }, }, }, ]); return result[0] || null; // 聚合返回数组,取第一个匹配结果 } }
方法二:代码层面处理查询结果
如果不需要数据库层面的聚合,也可以先查询原始数据,再在代码中手动处理数组:
import { Injectable } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { Model } from 'mongoose'; import { YourDocument, YourModelName } from './schemas/your.schema'; @Injectable() export class YourService { constructor( @InjectModel(YourModelName) private readonly yourModel: Model<YourDocument>, ) {} async findByIdWithGroupedRooms(id: string) { // 查询原始文档 const doc = await this.yourModel.findById(id).exec(); if (!doc) return null; // 用Map按name分组收集workId const roomGroup = new Map<string, string[]>(); doc.rooms.forEach(item => { if (!roomGroup.has(item.name)) { roomGroup.set(item.name, []); } roomGroup.get(item.name)?.push(item.workId); }); // 转换为目标格式的rooms数组 const formattedRooms = Array.from(roomGroup.entries()).map(([name, workIds]) => ({ name, workIds, })); // 返回最终结构 return { _id: doc._id, organization: doc.organization, rooms: formattedRooms, }; } }
内容的提问来源于stack exchange,提问作者Takiuddin Ahmed
相关产品推荐
相关产品推荐

