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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 03:03:14