【问题标题】:mongo range-based pagination with linq使用 linq 的 mongo 基于范围的分页
【发布时间】:2018-02-28 07:56:34
【问题描述】:

可以使用 mongo linq 进行基于范围的分页,或者我最好使用 filter 路由。以下是我手头的情况:

我将 ID 存储和生成为 mongo ObjectIds,但在我的域中将它们视为 strings

    BsonIgnoreIfDefault]
    [BsonRepresentation(BsonType.ObjectId)]
    [BsonId(IdGenerator = typeof(StringObjectIdGenerator))]
    public string Id { get; set; }

我正在尝试

var result = await _collection.AsQueryable()
         .Where(m => m.Id > afterId) // '>' illegal with strings
         .OrderBy(m => m.Id)
         .ToListAsync(); 

Error CS0019 Operator '>' cannot be applied to operands of type 'string' and 'string'.

另一种选择。我的 ID 是 mongo 生成的 ObjectId,我在过滤器中比较它们:

var idFilter = Builders<T>.Filter.Gt(m => m.Id, afterId);
result = await _collection.Find(idFilter).ToListAsync();

【问题讨论】:

  • 注意:如果您想知道某个对象是否在 另一个对象之后生成,您应该 依赖 objectId 为“更大”(在字典顺序)比另一个。请参阅:stackoverflow.com/questions/31057827/…
  • 现在,关于您的确切问题,在 C# 中查看一个字符串是否比另一个“更大”,您可以使用 String.Compare 。 String.Compare(a, b) 如果 a 小于 b,则为 -1,如果相等,则为 0,如果 a 大于 b,则为 1。
  • 嗨@Pac0 感谢 cmets。我不太关心哪个对象是在哪个对象之后生成的,只要它们不会影响我的分页。我主要关心的只是deep 不重复地翻阅结果。
  • 我认为字符串比较不会用 linq 处理(尽管您可以尝试:.Where(m =&gt; String.Compare(m.Id, afterId) &gt; 1))。要进行范围分页,我没有解决方案。不过,支持 linq TakeSkip,因此您可以进行一些基于大小的分页。但这似乎不是你想要的。
  • 如果可以选择,您可以在文档中添加另一个字段数字 id,然后您的第一个查询就可以工作

标签: c# mongodb linq


【解决方案1】:

如果您希望进行字符串比较,比较 'string1 > string2' 将使用 C# String.Compare(string1, string2) == 1 编写。

但是,阅读the docs on C# driver,mongodb 的 Linq 适配器似乎还不能翻译这个,所以 .Where(m =&gt; String.Compare(m.Id, afterId) == 1) 很可能被简单地忽略/失败。 (编辑:根据您的评论,它会给出一条错误消息)

作为替代方案,您可以:

  • 添加不同的数字 id 字段(唯一和索引)以允许通过 Linq 进行排序(有点丑陋和矫枉过正,但可能是一种可能性)

  • 按大小分页,而不是使用 TakeSkip 的 id 范围分页,这已受支持,如下所示:


/// take the results 2001-3000 in the list ordered by id.
var result = await _collection.AsQueryable()
     .OrderBy(m => m.Id)
     .Skip(2000)
     .Take(1000)
     .ToListAsync(); 

【讨论】:

  • 我想尽可能避免skip,因为我在某处读到它是影响性能的那个。由于我的用例只是加载所有记录(严格用于我的 api 内部使用),我正在考虑通过 FindAsyncIQueryable 通过 AsQueryable 公开 IAsyncCursor 如上所述。然后求助于mongodb默认排序进行排序。然后只是foreach 我使用记录的地方。这听起来是个好主意吗?
  • 不是使用 IAsyncCursor 的专家,并且不确定我是否非常了解其中的含义。如果在您的情况下内存不是问题,您可以加载所有记录,然后在已加载的实际 C# 记录列表中,您将能够毫无问题地使用 .Where(m =&gt; String.Compare(m.Id, afterId) == 1),因为这将是 Linq to Object 而不是Linq 到 mongodb 查询了
  • 另外,我建议您尝试使用Skip 看看您的情况是否实际上存在性能问题。
猜你喜欢
  • 2011-10-11
  • 1970-01-01
  • 2016-08-25
  • 2023-03-12
  • 1970-01-01
  • 2018-06-20
  • 2010-09-08
  • 2020-08-25
  • 2021-08-21
相关资源
最近更新 更多