【问题标题】:C# mongo paging with aggregates带有聚合的 C# mongo 分页
【发布时间】:2022-01-27 09:11:15
【问题描述】:

我有一个 mongodb 集合,其中有多个学生,每个学生都有多个这样的记录

[
  {
    "studentid": "stu-1234",
    "dept": "geog",
    "Status": 1,
    "CardSwipeTimestamp": "2021-11-25T10:50:00.5230694Z"
  },
  {
    "studentid": "stu-1234",
    "dept": "geog",
    "Status": 2,
    "CardSwipeTimestamp": "2021-11-25T11:50:00.5230694Z"
  },
  {
    "studentid": "stu-abc",
    "dept": "geog",
    "Status": 11,
    "CardSwipeTimestamp": "2021-11-25T09:15:00.5230694Z"
  },
  {
    "studentid": "stu-abc",
    "dept": "geog",
    "Status": 21,
    "CardSwipeTimestamp": "2021-11-25T11:30:00.5230694Z"
  }
]

我有一个聚合查询正在运行并在 C# Dotnet Core 3.1 中获取多个这样的记录。该查询根据学生 id 和部门名称列表获取每个学生的最新记录,在这种情况下,它将获取 sid=stu-abc 的一条记录和 sid=stu-1234 的一条记录。

string [] sids   = { array of Student ids here };
string deptName = "math";
var pipeline = new BsonDocument[]
    {
        new BsonDocument("$match",
            new BsonDocument
            {
                {"studentid", new BsonDocument("$in",BsonArray.Create(sids))},
                {"dept",dept}
            }
        ),
            new BsonDocument("$sort",new BsonDocument("CardSwipeTimestamp", -1)),
                               
            new BsonDocument("$group",
                new BsonDocument{
                        { "_id",
                            new BsonDocument
                            {
                                { "studentid","$studentid" },
                                { "dept","$dept"}
                            }
                        },
                        { "Status",new BsonDocument("$first", "$Status")},
                        { "CardSwipeTimestamp",new BsonDocument("$first", "$CardSwipeTimestamp")}
                    }
                ),
       new BsonDocument("$project",
            new BsonDocument
            {
                { "_id", 0 },
                { "studentid", "$_id.studentid" },
                { "dept", "$_id.dept" },
                { "Status", "$Status" },
                { "CardSwipeTimestamp", "$CardSwipeTimestamp" }
            }
        ),
         new BsonDocument("$skip",0),
         new BsonDocument("$limit",3),
    };

collectionName.Aggregate<BsonDocument>(pipeline).ToList()

假设我的收藏有数百万个带有 1000 个学生 ID 的条目,我该如何提供一种方法来返回一个分页列表?我不想获取所有记录,然后使用 C# linq 对它们进行分页。我可以将一些页面参数发送到上面的管道,这样我就可以一次获取 20 条记录,然后移动到与第一条记录有偏移的下 20 条记录?在这方面需要一些帮助。

编辑

如上所述应用跳过和限制后,我只得到分页的日期,但它并不一致。如果我将 skip 作为 0 和 limit=1 传入,它会得到 3 条记录,但是当我翻到下一页时,有时我会得到上一页中的记录。

【问题讨论】:

  • $group 不对其输出文档进行排序。
  • @Valijon 我已经编辑了我的问题。检查我如何应用带有跳过和限制的排序。您是否认为在应用跳过和限制时导致响应不一致的问题是缺少排序?

标签: c# mongodb .net-core mongodb-query


【解决方案1】:

$sort 之后,您需要添加这两个:$skip$limit。下面是一个例子(当然你需要参数化它)。

new BsonDocument("$skip", 0},
new BsonDocument("$limit", 20},

这将启用服务器端分页。跳过/限制需要排序,否则您的结果不确定。

现在这种方法有效,但并非完全最优。为了完全优化,您需要记住最后一页的最后一条记录并从那里开始,因为 skip 从排序集中的第一个匹配项开始按顺序跳过记录(这意味着扫描,因此线性;记住文档可以让您进行查找,即 O(1))。这超出了您的问题范围,但这里有 resourceanother

【讨论】:

  • 感谢您的回复。我确实尝试了这种限制跳过的方法,并且确实注意到它每次都会带回一组不同的记录,即使我没有更改跳过和限制参数。这是我尝试过的mongoplayground.net/p/E26o3YILVzt
  • 我认为您可能需要在分组之前移动跳过/限制。或者您的排序可能需要包含您的分组(复合排序)。无论哪种方式,在像 group 这样的非确定性操作之后跳过/限制都可能不是您想要的。
  • 谢谢。这似乎在 mongo 操场上工作,但是当我把它放在 c# 代码中时,我在使用 skip=0 和 limit=3 时只得到 1 条记录。它返回的那一条记录是第三条记录。
  • 必须记住最后一条记录,不能在无状态的基于 api 的环境中工作。我不能指望客户端发送最后一条记录以及限制和跳过。我无法控制客户端代码。那么这是对 mongo 驱动程序方面的限制吗?
  • 没错,您必须记住 API 中某处的文档(例如,查询参数的缓存-->最后一个文档)。不理想,因为有状态,我同意你。
猜你喜欢
  • 1970-01-01
  • 2017-03-03
  • 1970-01-01
  • 2013-07-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-08
  • 1970-01-01
相关资源
最近更新 更多