Express.js接口GET请求中如何排序Mongoose数组字段并截取最新5条
问题与解决方案
问题描述
我是Express、MongoDB、Mongoose新手,现有以下代码:
User Schema
const mongoose = require('mongoose') const userSchema = new mongoose.Schema({ name: { type: String }, subscriptions: [{ userID: { type: String, required: true, }, subscriptionDate: { type: Date, required: true, default: Date.now } }] })
routes.js
const express = require('express') const router = express.Router() const User = require('User') router.get('/', async (req, res) => { try { const users = await User.find() res.json(users) } catch (err) { res.status(500).json({message: err.message}) } })
server.js
require('dotenv').config(); const express = require('express'); const app = express(); const mongoose = require('mongoose'); mongoose.connect('mongodb://localhost/subscribers'); const db = mongoose.connection; db.on('error', (error) => console.error(error)); db.once('open', () => console.log('Connected to Database')); app.use(express.json()); const router = require("./routes"); app.use('/routes', router); app.listen(3000, () => console.log('Server Started.'))
发起GET请求时,我希望每个用户的subscriptions数组按subscriptionDate字段倒序排序(取最新的),仅显示最新5条记录,同时保留用户其他全部信息。之前尝试collections.find().sort()会把所有用户按订阅排序,用aggregate([$unwind])会拆分用户文档,都不符合需求,请问该如何实现?
解决方案
你可以使用MongoDB的聚合管道,通过$project结合排序、截取操作符实现每个用户的subscriptions数组内部处理,同时保留其他字段。以下是几种可行方法:
方法一:使用$sortArray(MongoDB 5.2+ 推荐)
修改routes.js中的GET请求处理代码:
router.get('/', async (req, res) => { try { const users = await User.aggregate([ { $project: { name: 1, // 保留name字段,其他需保留的字段按此格式添加 subscriptions: { $slice: [ { $sortArray: { input: "$subscriptions", sortBy: { subscriptionDate: -1 } // -1表示倒序,最新记录在前 } }, 5 // 仅取前5条 ] } } } ]) res.json(users) } catch (err) { res.status(500).json({message: err.message}) } })
代码说明:
$sortArray:对单个用户的subscriptions数组按subscriptionDate倒序排序$slice:从排序后的数组中截取前5条记录$project:指定需要保留的用户字段,1表示保留该字段,若有其他字段(如邮箱)需保留,直接添加email: 1即可
方法二:兼容低版本MongoDB(低于5.2)
如果你的MongoDB版本不支持$sortArray,可以用$map结合$sort替代:
router.get('/', async (req, res) => { try { const users = await User.aggregate([ { $project: { name: 1, subscriptions: { $slice: [ { $map: { input: { $sort: { input: "$subscriptions", sortBy: { subscriptionDate: -1 } } }, as: "sub", in: "$$sub" } }, 5 ] } } } ]) res.json(users) } catch (err) { res.status(500).json({message: err.message}) } })
方法三:查询后用JavaScript处理
适合数据量较小的场景,获取数据后在服务器端用JS处理数组:
router.get('/', async (req, res) => { try { const users = await User.find() const processedUsers = users.map(user => { // 转换为普通对象,避免修改Mongoose原始文档 const userObj = user.toObject() // 按subscriptionDate倒序排序,取前5条 userObj.subscriptions = userObj.subscriptions .sort((a, b) => b.subscriptionDate - a.subscriptionDate) .slice(0, 5) return userObj }) res.json(processedUsers) } catch (err) { res.status(500).json({message: err.message}) } })
内容的提问来源于stack exchange,提问作者Lee
相关产品推荐
相关产品推荐

