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

C# MongoDB聚合分组内实现分页报错:调用Take方法不被支持

分组后每组分页报错问题

我使用MongoDB的Aggregate方法实现了分组功能,希望为每个分组实现分页,但在Group阶段内调用Skip或Take方法时代码报错,仅调用Take()方法时会触发该错误。

我的实现代码

var queryResult = await collection.Aggregate().Match(expr).Sort(sort)
                                  .Group(
                                    x => x.ApprovalStatus.Value,
                                    g => new
                                    {
                                        approvalStatus = g.Key,
                                        data = g.Select(f => new FtagDashboardDTO
                                        {
                                            Id = f.Id,
                                            FtagId = f.FtagId,
                                            Title = f.Title,
                                            Assignee = f.Assignee,
                                            ApprovalStatus = f.ApprovalStatus,
                                            Priority = f.Priority,
                                            DueDate = f.DueDate
                                        }).Take(5).ToList()
                                    })
                                  .ToListAsync();

报错信息

Specified method is not supported.:: StackTrace ::     at MongoDB.Driver.Linq.Linq2Implementation.Processors.AccumulatorBinder.GetAccumulatorArgument(Expression node)\r\n   at MongoDB.Driver.Linq.Linq2Implementation.Processors.AccumulatorBinder.TryGetAccumulatorTypeAndArgument(PipelineExpression node, AccumulatorType& accumulatorType, Expression& argument)\r\n   at MongoDB.Driver.Linq.Linq2Implementation.Processors.AccumulatorBinder.VisitPipeline(PipelineExpression node)\r\n   at MongoDB.Driver.Linq.Linq2Implementation.Processors.EmbeddedPipeline.EmbeddedPipelineBinder.Bind(Expression node, IBindingContext parent)\r\n   at MongoDB.Driver.Linq.Linq2Implementation.Processors.SerializationBinder.BindEmbeddedPipeline(MethodCallExpression node)\r\n   at MongoDB.Driver.Linq.Linq2Implementation.Processors.SerializationBinder.VisitMethodCall(MethodCallExpression node)\r\n   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)\r\n   at MongoDB.Driver.Linq.Linq2Implementation.Processors.SerializationBinder.Visit(Expression node)\r\n   at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)\r\n   at System.Linq.Expressions.ExpressionVisitor.VisitNew(NewExpression node)\r\n   at System.Linq.Expressions.NewExpression.Accept(ExpressionVisitor visitor)\r\n   at MongoDB.Driver.Linq.Linq2Implementation.Translators.AggregateGroupTranslator.BindGroup[TKey,TDocument,TResult](PipelineBindingContext bindingContext, Expression`1 groupProjector, IBsonSerializer`1 parameterSerializer, Expression keySelector)\r\n   at MongoDB.Driver.Linq.Linq2Implementation.Translators.AggregateGroupTranslator.Translate[TKey,TDocument,TResult](Expression`1 idProjector, Expression`1 groupProjector, IBsonSerializer`1 parameterSerializer, IBsonSerializerRegistry serializerRegistry, ExpressionTranslationOptions translationOptions)\r\n   at MongoDB.Driver.GroupExpressionProjection`3.Render(IBsonSerializer`1 documentSerializer, IBsonSerializerRegistry serializerRegistry, LinqProvider linqProvider)\r\n   at MongoDB.Driver.PipelineStageDefinitionBuilder.<>c__DisplayClass19_0`2.<Group>b__0(IBsonSerializer`1 s, IBsonSerializerRegistry sr, LinqProvider linqProvider)\r\n   at MongoDB.Driver.AppendedStagePipelineDefinition`3.Render(IBsonSerializer`1 inputSerializer, IBsonSerializerRegistry serializerRegistry, LinqProvider linqProvider)\r\n   at MongoDB.Driver.MongoCollectionImpl`1.AggregateAsync[TResult](IClientSessionHandle session, PipelineDefinition`2 pipeline, AggregateOptions options, CancellationToken cancellationToken)\r\n   at MongoDB.Driver.MongoCollectionImpl`1.UsingImplicitSessionAsync[TResult](Func`2 funcAsync, CancellationToken cancellationToken)\r\n   at MongoDB.Driver.IAsyncCursorSourceExtensions.ToListAsync[TDocument](IAsyncCursorSource`1 source, CancellationToken cancellationToken)\r\n   at ProfessionalMaintenance.API.Infrastructure.Repostiories.FtagRepository.GetKanbanByQuery(FtagDashboardFilterDTO filter) in C:\\development\\leansuite\\lean-suggestion-backend\\src\\Services\\ProfessionalMaintenance\\ProfessionalMaintenance.API\\Infrastructure\\Repostiories\\FtagRepository.cs:line 263\r\n   at ProfessionalMaintenance.API.Controllers.FtagApiController.GetDashboard(FtagDashboardFilterDTO request) in C:\\development\\leansuite\\lean-suggestion-backend\\src\\Services\\ProfessionalMaintenance\\ProfessionalMaintenance.API\\Controllers\\FtagApiController.cs:line 183\r\n   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)\r\n   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Logged|12_1(ControllerActionInvoker invoker)\r\n   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)\r\n   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)\r\n   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)\r\n   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)\r\n   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|26_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)

解决方案

MongoDB的Group阶段不支持直接使用Linq的Take()方法,因为该方法无法被翻译为对应的MongoDB聚合操作符,需改用以下方式实现每组分页:

方法1:分组后通过Project阶段使用Slice截取

先将每组数据全部收集到数组中,再在Project阶段用Slice()方法(对应MongoDB原生$slice操作符)截取指定数量的元素:

var queryResult = await collection.Aggregate()
    .Match(expr)
    .Sort(sort)
    .Group(
        x => x.ApprovalStatus.Value,
        g => new
        {
            approvalStatus = g.Key,
            data = g.Select(f => new FtagDashboardDTO
            {
                Id = f.Id,
                FtagId = f.FtagId,
                Title = f.Title,
                Assignee = f.Assignee,
                ApprovalStatus = f.ApprovalStatus,
                Priority = f.Priority,
                DueDate = f.DueDate
            }).ToList()
        })
    .Project(g => new
    {
        g.approvalStatus,
        data = g.data.Slice(0, 5) // 从索引0开始截取5个元素,等价于Take(5)
    })
    .ToListAsync();

方法2:Group阶段推送原始文档,再投影截取并映射DTO

如果不需要提前映射DTO,可先推送原始文档到数组,再在投影阶段截取并转换为目标DTO,这种方式更高效:

var queryResult = await collection.Aggregate()
    .Match(expr)
    .Sort(sort)
    .Group(
        x => x.ApprovalStatus.Value,
        g => new
        {
            approvalStatus = g.Key,
            data = g.Push(f => f) // 推送分组内的原始文档
        })
    .Project(g => new
    {
        g.approvalStatus,
        data = g.data.Slice(0, 5).Select(f => new FtagDashboardDTO
        {
            Id = f.Id,
            FtagId = f.FtagId,
            Title = f.Title,
            Assignee = f.Assignee,
            ApprovalStatus = f.ApprovalStatus,
            Priority = f.Priority,
            DueDate = f.DueDate
        }).ToList()
    })
    .ToListAsync();

关键说明

  • Slice(startIndex, count)方法是MongoDB驱动提供的扩展方法,对应原生$slice聚合操作符,可在Project阶段实现数组截取。
  • Linq的Take()仅能在常规查询中使用,无法在Aggregate的Group阶段被翻译为MongoDB可执行的操作,因此必须替换为Slice()。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 16:22:15