You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何统计Mongoose查询结果中用户借阅次数并生成统计数组

解决用户借阅次数统计分组问题

问题背景

现有MongoDB模型及查询数据如下,需要将用户借阅记录按name和course分组,统计每组的借阅次数,转换成指定格式。

模型文件

models/return.js

const mongoose = require('mongoose')
const returnSchema = new mongoose.Schema({
    userId: {
        type: mongoose.Schema.ObjectId,
        ref: 'User'
    },
    bookId: [{
        type: mongoose.Schema.ObjectId,
        ref: 'Book'
    }],
    course: {
        type: String,
    },
    returnedDate: {
        type: Date,
    }
})
module.exports = mongoose.model('Return', returnSchema);

models/user.js

const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
    name: {
        type: String,
        required: [true, 'Please enter your name'],
    },
    course: {
        type: String,
    },
    section: {
        type: String,
    },
    email: {
        type: String,
        required: [true, 'Please enter your email'],
        unique: true,
        validate: [validator.isEmail, 'Please enter valid email address']
    },
    password: {
        type: String,
        required: [true, 'Please enter your password'],
        select: false
    },
    resetPasswordToken: String,
    resetPasswordExpire: Date
})
module.exports = mongoose.model('User', userSchema);

现有数据

提取name和course后的数组:

[
  {name: 'user1', course: 'BSIT'},
  {name: 'user1', course: 'BSIT'},
  {name: 'user1', course: 'BSIT'},
  {name: 'user1', course: 'BSIT'},
  {name: 'user3', course: 'BTIT'},
  {name: 'user3', course: 'BTIT'},
  {name: 'user2', course: 'BSIT'}
]

目标格式

[
  {name: 'user1', course: 'BSIT', count:'3'},
  {name: 'user2', course: 'BSIT', count:'2'},
  {name: 'user3', course: 'BTIT', count:'2'}
]

解决方案

方案一:MongoDB聚合查询(推荐)

直接在数据库层完成关联、分组和统计,避免大量数据传输,性能更优。

const borrowerRanking = await Return.aggregate([
  // 关联User集合,获取用户的name和course
  {
    $lookup: {
      from: 'users', // User模型对应的集合名,注意是复数小写形式
      localField: 'userId',
      foreignField: '_id',
      as: 'userInfo'
    }
  },
  // 展开userInfo数组($lookup返回的是数组,需展开为单个对象)
  { $unwind: '$userInfo' },
  // 按name和course分组,统计借阅次数
  {
    $group: {
      _id: {
        name: '$userInfo.name',
        course: '$userInfo.course'
      },
      count: { $sum: 1 }
    }
  },
  // 调整字段格式,转换成目标结构
  {
    $project: {
      _id: 0,
      name: '$_id.name',
      course: '$_id.course',
      count: { $toString: '$count' } // 若需数字类型可去掉$toString
    }
  }
])

方案二:JavaScript层面处理已有数组

如果已经获取了提取后的borrowerArr,可以用reduce方法分组计数:

const result = Object.values(borrowerArr.reduce((acc, item) => {
  // 用name+course的组合作为唯一标识键
  const key = `${item.name}-${item.course}`;
  if (!acc[key]) {
    // 首次出现该用户,初始化计数
    acc[key] = { ...item, count: '1' };
  } else {
    // 累计计数
    acc[key].count = `${parseInt(acc[key].count) + 1}`;
  }
  return acc;
}, {}));

内容的提问来源于stack exchange,提问作者sheynn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 03:20:52