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

如何在MongoDB及C# MongoDB.Driver中获取文档的最后N个子文档

在MongoDB.Driver(C#)中对指定文档的子数组排序并截取最后N条

我来帮你解决这个问题——在C#的MongoDB.Driver中,对指定文档的子数组排序并截取最后N条确实不能直接用普通的find方法,得借助聚合管道来实现,下面分步骤给你详细方案:

一、先理解MongoDB底层聚合逻辑

首先用Mongo Shell写出核心逻辑,方便你理解原理:

db.foo.aggregate([
    // 第一步:匹配到你需要的目标文档(ID=A)
    { $match: { _id: "10000" } },
    // 第二步:对channels子数组按指定字段排序(这里按id升序,可按需调整)
    { $addFields: {
        channels: {
            $sortArray: {
                input: "$channels",
                sortBy: { id: 1 } // 1=升序,-1=降序
            }
        }
    }},
    // 第三步:截取排序后的最后N条(这里N=2)
    { $addFields: {
        channels: { $slice: ["$channels", -2] } // 负数表示从数组末尾取N个
    }}
])

注意:$sortArray是MongoDB 5.2及以上版本支持的语法,性能更优;如果你的MongoDB版本低于5.2,我会在后面补充兼容方案。

二、C# MongoDB.Driver实现代码

首先定义和你的文档结构对应的实体模型:

using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using System.Collections.Generic;

public class Customer
{
    [BsonId]
    public string Id { get; set; }
    public string Password { get; set; }
    public string Name { get; set; }
    public List<Channel> Channels { get; set; }
}

public class Channel
{
    public string Id { get; set; }
    public string Name { get; set; }
    public bool Enabled { get; set; }
}

然后编写聚合查询的C#代码:

using MongoDB.Driver;
using System.Threading.Tasks;

// 假设你已经获取了MongoDatabase实例
var collection = mongoDatabase.GetCollection<Customer>("foo");
string targetDocumentId = "10000"; // 你要查找的ID=A
int takeLastN = 2; // 要截取的最后N条子文档

// 构建聚合管道
var pipeline = new BsonDocument[]
{
    // 匹配目标文档
    new BsonDocument("$match", new BsonDocument("_id", targetDocumentId)),
    // 对channels子数组排序
    new BsonDocument("$addFields", new BsonDocument("channels",
        new BsonDocument("$sortArray", new BsonDocument
        {
            { "input", "$channels" },
            { "sortBy", new BsonDocument("id", 1) } // 可修改排序字段和方向,比如按_id降序就是new BsonDocument("_id", -1)
        }))),
    // 截取最后N条
    new BsonDocument("$addFields", new BsonDocument("channels",
        new BsonDocument("$slice", new BsonArray { "$channels", -takeLastN })))
};

// 执行聚合并获取结果
var result = await collection.Aggregate<Customer>(pipeline).FirstOrDefaultAsync();

三、兼容MongoDB 5.2以下版本的方案

如果你的MongoDB版本较低,不支持$sortArray,可以用$unwind+$sort+$group的组合实现:

Mongo Shell示例

db.foo.aggregate([
    { $match: { _id: "10000" } },
    { $unwind: "$channels" }, // 打散子数组为单个文档
    { $sort: { "channels.id": 1 } }, // 对打散后的子文档排序
    { $group: { // 重新组合为原文档结构
        _id: "$_id",
        password: { $first: "$password" },
        name: { $first: "$name" },
        channels: { $push: "$channels" }
    }},
    { $project: { // 截取最后N条
        password: 1,
        name: 1,
        channels: { $slice: ["$channels", -2] }
    }}
])

对应的C#代码

var pipelineOldVersion = new BsonDocument[]
{
    new BsonDocument("$match", new BsonDocument("_id", targetDocumentId)),
    new BsonDocument("$unwind", "$channels"),
    new BsonDocument("$sort", new BsonDocument("channels.id", 1)),
    new BsonDocument("$group", new BsonDocument
    {
        { "_id", "$_id" },
        { "password", new BsonDocument("$first", "$password") },
        { "name", new BsonDocument("$first", "$name") },
        { "channels", new BsonDocument("$push", "$channels") }
    }),
    new BsonDocument("$project", new BsonDocument
    {
        { "password", 1 },
        { "name", 1 },
        { "channels", new BsonDocument("$slice", new BsonArray { "$channels", -takeLastN }) }
    })
};

var resultOldVersion = await collection.Aggregate<Customer>(pipelineOldVersion).FirstOrDefaultAsync();

小贴士:优先使用$sortArray的方案,因为$unwind会把子数组打散成多个文档,当子数组数据量很大时,性能会明显下降。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 07:33:50