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

如何使用Mongoose获取数组中各ID对应的最后一条文档?

Answer

Absolutely, you can pull this off entirely with Mongoose (thanks to MongoDB's aggregation framework)—no manual post-processing of results needed. Here's how to fetch the latest QuizResult document for each levelAnswered ID in your levelIds array:

Step-by-Step Aggregation Pipeline

We'll use a series of aggregation stages to filter, sort, group, and reshape your data to get exactly what you need:

QuizResult.aggregate([
  // 1. Narrow down to only the relevant documents for the user and target levels
  {
    $match: {
      levelAnswered: { $in: levelIds },
      answeredByUser: result.applicant._id
    }
  },
  // 2. Sort documents so the newest entry for each level comes first
  {
    $sort: { created: -1 }
  },
  // 3. Group by level ID, keeping only the latest document in each group
  {
    $group: {
      _id: "$levelAnswered",
      latestResult: { $first: "$$ROOT" } // $$ROOT refers to the entire document object
    }
  },
  // 4. Optional: Reshape output to match the structure of a regular find() result
  {
    $replaceRoot: { newRoot: "$latestResult" }
  }
])
.then(latestResults => {
  // latestResults is an array of the most recent QuizResult per levelId
  console.log(latestResults);
})
.catch(err => {
  console.error("Error fetching latest results:", err);
});

Breakdown of Each Stage:

  • $match: Filters out irrelevant documents upfront, reducing the data we process in later stages.
  • $sort: Orders matched documents by created date in descending order, ensuring the newest entry for each level is at the top of its group.
  • $group: Clusters documents by levelAnswered ID. Using $first: "$$ROOT" grabs the very first (and thus latest) document from each sorted group.
  • $replaceRoot: Optional but convenient—this moves the nested latestResult object up to the root of each result entry, making the output look like what you'd get from a standard find() query.

Handling Populated Fields

If you need to resolve the referenced fields (like answeredByUser or levelAnswered), you have two straightforward options:

Option 1: Use Mongoose's populate After Aggregation

Aggregation results don't auto-populate, but you can run populate on the returned array:

QuizResult.aggregate([/* ... pipeline as above ... */])
.then(results => {
  return QuizResult.populate(results, { path: 'levelAnswered answeredByUser' });
})
.then(populatedResults => {
  // Now populatedResults includes the full referenced documents
});

Option 2: Add $lookup to the Aggregation Pipeline

You can directly join with referenced collections in the pipeline using MongoDB's $lookup stage. For example, to populate levelAnswered:

QuizResult.aggregate([
  // ... match, sort, group, replaceRoot stages ...
  {
    $lookup: {
      from: "quizlevels", // Name of your QuizLevel collection (Mongoose pluralizes model names by default)
      localField: "levelAnswered",
      foreignField: "_id",
      as: "levelAnswered"
    }
  },
  { $unwind: "$levelAnswered" } // Convert the array from $lookup to a single object
])
// ... rest of your code

Why This Is Better Than Multiple Queries

Using aggregation is way more efficient than running a separate findOne for each levelId (which would trigger N database calls for N IDs). The pipeline handles everything in one round trip, cutting down on network overhead and improving performance.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 07:27:40