首页 > 解决方案 > 如何使用 C# 中的 mongo 驱动程序按条件排序

问题描述

我一直在关注 mongo 驱动程序(2.4)文档,目前正试图对排序设置条件。

按照文档,我得到了一个 AsQueryable 实例,并使用了传入表达式的 where 函数。直到我想通过条件而不是字段进行排序之前,它都可以正常工作。

这是我想订购的:

db.child.AsQueryable().Where(expression).OrderBy(x=> x.parentId == someParentId); 

这应该是类似于 linq 的东西

SELECT * FROM child
ORDER BY
  CASE parentId
  WHEN someParentId THEN 1
  ELSE 2 END,
  parentId; 

但是,目前,在运行 OrderBy 条件后,我相信它正在评估表达式,因为从调试器中我可以看到表达式更改如下所示:

在此处输入图像描述

所以两个主要问题是:

  1. 如何使用 .net mongo 驱动程序按布尔表达式排序。
  2. 为什么要转换如屏幕截图中所示的表达式?

Mongo 驱动程序文档 (2.4)

标签: c#mongodbmongodb-queryaggregation-frameworkmongodb-.net-driver

解决方案


正如 MongoDB C# 驱动程序文档所述(来自粘贴的链接):

该驱动程序包含一个针对聚合框架的 LINQ 实现。

所以在聚合框架中必须有相应的操作才能从 LINQ 中进行翻译。您调用.AsQueryable()这意味着您可以使用 LINQ 语法构建表达式,但是当需要转换为聚合框架时它会失败。不幸的是,您不能在$sort中使用表达式,这就是您的代码会失败的原因。

要解决此问题,您可以使用$addFields阶段添加一个附加字段MatchesParent并按此字段排序。

假设您的模型由以下类表示:

public class Model
{
    [BsonId]
    public ObjectId Id { get; set; }
    public string ParentId { get; set; }
    // some other properties
}

您可以添加以下类:

public class ModelResult: Model
{
    public bool MatchesParent { get; set; }
}

然后你可以定义$addFieldsasPipelineStageDefinitionnameof操作符来保持它的强类型:

PipelineStageDefinition<Model, ModelResult> addFields = new BsonDocument() {
            { "$addFields", new BsonDocument() {
                    { nameof(ModelResult.MatchesParent), new BsonDocument() {
                        { "$eq", new BsonArray() { "$" + nameof(Model.ParentId), someParentId } }
                    }
                }
            }
        }
    };

var result = Col.Aggregate()
                .Match(expression)                           
                .AppendStage(addFields)
                .SortByDescending(x => x.MatchesParent)
                .ToList();

推荐阅读