IQueryable 复杂顺序 $sort 中仅允许使用字段

2024-02-12

我想对列表进行排序。当它是IEnumerable时它工作正常,但是我将其更改为IQueryable来查询MongoDB时,它不起作用。给我这个错误

System.NotSupportedException:“$sort 中仅允许使用字段。”

//Query 1
var query = from d in list
        orderby
             d.Item.Value1 + d.Item.Value2 descending
        select d;

//Query 2
var query = from d in list
       orderby
            RecommendationFormula(d) descending
       select d;

private double RecommendationFormula(IItem d)
{
    var quality = ((int)(d.ValueX) / 18.0) * 50.0;
    var recent = ((DateTime.MinValue - (d.Item.Released ?? DateTime.MinValue)).TotalDays / (DateTime.MinValue - new DateTime(1990, 1, 1)).TotalDays) * 30;
    var rating = ((d.Item.XRating + d.Item.YRating) / 20) * 15;
    var quantity = (Quantity(d) / 1000.0) * 5;
    return quality + rating + recent + quantity;
}

我也知道它不支持函数(如查询 2 所示),但当我尝试 ToList() 列表时,查询 1 也给出了错误。 如何为 IQueryable 列表编写这种复杂的排序?


正如例外中所述,在 LINQ 中配置排序的类型化方法仅支持字段,而不支持计算值。看起来这是基于服务器的限制this https://docs.mongodb.com/manual/reference/operator/aggregation/sort/#mongodb-pipeline-pipe.-sort。所以可以通过添加投影来解决:

        var query = from d in list
                    select new { Sum = d.Item.Value1 + d.Item.Value2, Item = d.Item } into projected
                    orderby projected.Sum descending
                    select projected;

触发此 MQL:

{
    "aggregate": "coll",
    "pipeline": [{
            "$project": {
                "Sum": {
                    "$add": ["$Item.Value1", "$Item.Value2"]
                },
                "Item": "$Item",
                "_id": 0
            }
        }, {
            "$sort": {
                "Sum": -1
            }
        }
    ]
}

您可以在那里添加更复杂的逻辑,但不要期望任何东西太复杂,在您的特定情况下,对 Timespan 属性的支持将触发不受支持的异常,我不确定服务器是否在 .net 中具有等效的 Timespan 逻辑。

如果您仍然需要查看更复杂的场景,这些场景会触发类型化 LINQ 查询不受支持的异常,那么您有 2 个选择:

  1. 看看最新的LINQ3执行 https://mongodb.github.io/mongo-csharp-driver/2.14/reference/driver/crud/linq3/。我知道与 LINQ2(默认)相比,它支持 LINQ 查询中的更多不同情况,但我没有这方面的经验,因此需要更多调查。
  2. 您可以查看您的目标是否可以使用 MQL 服务器查询本身进行存档(这肯定比使用 LINQ 提供程序实现的情况支持更多的情况)。如果您可以使用服务器构造您需要的查询syntax https://docs.mongodb.com/manual/aggregation/并在 mongo shell 中获得所需的结果,您可以将此原始 MQL 传递到 C# 驱动程序中(注意原始 MQL 内的所有定义应与服务器表示它的方式匹配)。看this https://stackoverflow.com/questions/68395490/how-to-use-raw-mongodb-aggregation-query-in-c/68397480#68397480了解详情。

UPDATE:

  1. 看起来像$substractLINQ2 支持:

         var query = from d in list
                     select new { Sum = (DateTime.Now - d.Item.Released), Item = d.Item } into projected
                     orderby projected.Sum descending
                     select projected;
    

但它无法提取TotalDays和类似的属性。然而,看起来服务器阶段通过 2 个运算符支持它:

  1. Example https://docs.mongodb.com/manual/reference/operator/aggregation/subtract/#subtract-milliseconds-from-a-date如何从数据中提取毫秒$substact.
  2. 你可以看看dateDiff https://docs.mongodb.com/manual/reference/operator/aggregation/dateDiff/新引入的运营商也。

想法是创建一个原始 MQL 请求,您可以在 shell 中检查该请求,类似于:

db.coll.aggregate(
[
// stage 1
{
    $addFields: {
        "DateDiff": {
            $dateDiff: {
                startDate: "$Item.Released",
                endDate: ISODate("2010-01-01"),
                unit: "day"
            }
        }
    }
},
// stage 2
{
    $addFields: {
        "ForSorting": {
            $divide : [ { $toInt : "$DateDiff"} , 9] // 9 is a random value, you can calculate it yourself 
        }
    }
},
// stage 3
{
    $sort : { "ForSorting" : -1 }
}
]
)

然后分别通过每个阶段AppendStage method.

NOTE:您可以将类型化阶段(如果支持)和具有原始 MQL 的阶段结合起来,类似于:

        var result = coll
            .Aggregate()
            .Match(c => c.Item != null) // just example of supported typed stage
            .AppendStage<BsonDocument>("{ $sort : { Released : 1 } }") // such simple `$sort` is supported in typed way, here is just an example how a raw query can be appended to the pipeline
            .ToList();

上述 LINQ 查询生成的 MQL 将为:

{
    "aggregate": "coll",
    "pipeline": [{
            "$match": {
                "Item": {
                    "$ne": null
                }
            }
        }, {
            "$sort": {
                "Released": 1
            }
        }
    ]
}

UPDATE2如果投影输出文档中的字段与输入文档中的字段匹配,您可以避免重新投影(即额外的服务器端步骤),而只需通过以下方式替换客户端上的输出序列化器As:

        var list = coll
            .Aggregate<Original>() // this class has only `Item` field
            .Project(i => new { Sum = i.Item.Value1 + i.Item.Value2, Item = i.Item }) // this expression can be generated dynamically
            .SortByDescending(s=>s.Sum)
            .As<Original>()
            .ToList();

上述情况生成的 MQL 将为:

{
    "aggregate": "coll",
    "pipeline": 
    [
        {
            "$project": {
                "Sum": {
                    "$add": ["$Item.Value1", "$Item.Value2"]
                },
                "Item": "$Item",
                "_id": 0
            }
        }, 
        {
            "$sort": {
                "Sum": -1
            }
        }
    ]
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

IQueryable 复杂顺序 $sort 中仅允许使用字段 的相关文章

  • 在模板类中声明模板友元类时出现编译器错误

    我一直在尝试实现我自己的链表类以用于教学目的 我在迭代器声明中指定了 List 类作为友元 但它似乎无法编译 这些是我使用过的 3 个类的接口 Node h define null Node
  • 没有特殊字符的密码验证器

    我是 RegEx 的新手 已经进行了大量搜索 但没有找到任何具体内容 我正在编写一个验证密码字符串的正则表达式 可接受的字符串必须至少具有 4 种字符类型中的 3 种 数字 小写字母 大写字母 特殊字符 我对包含有一个想法 也就是说 如果这
  • 在一个数据访问层中处理多个连接字符串

    我有一个有趣的困境 我目前有一个数据访问层 它必须与多个域一起使用 并且每个域都有多个数据库存储库 具体取决于所调用的存储过程 目前 我只需使用 SWITCH 语句来确定应用程序正在运行的计算机 并从 Web config 返回适当的连接字
  • std::vector 与 std::stack

    有什么区别std vector and std stack 显然 向量可以删除集合中的项目 尽管比列表慢得多 而堆栈被构建为仅后进先出的集合 然而 堆栈对于最终物品操作是否更快 它是链表还是动态重新分配的数组 我找不到关于堆栈的太多信息 但
  • 如何在 C# 中打开 Internet Explorer 属性窗口

    我正在开发一个 Windows 应用程序 我必须向用户提供一种通过打开 IE 设置窗口来更改代理设置的方法 Google Chrome 使用相同的方法 当您尝试更改 Chrome 中的代理设置时 它将打开 Internet Explorer
  • free 和 malloc 在 C 中如何工作?

    我试图弄清楚如果我尝试 从中间 释放指针会发生什么 例如 看下面的代码 char ptr char malloc 10 sizeof char for char i 0 i lt 10 i ptr i i 10 ptr ptr ptr pt
  • 从经典 ASP 调用 .Net C# DLL 方法

    我正在开发一个经典的 asp 项目 该项目需要将字符串发送到 DLL DLL 会将其序列化并发送到 Zebra 热敏打印机 我已经构建了我的 DLL 并使用它注册了regasm其次是 代码库这使得 IIS 能够识别它 虽然我可以设置我的对象
  • C++ 多行字符串原始文字[重复]

    这个问题在这里已经有答案了 我们可以像这样定义一个多行字符串 const char text1 part 1 part 2 part 3 part 4 const char text2 part 1 part 2 part 3 part 4
  • 方程“a + bx = c + dy”的积分解

    在等式中a bx c dy 所有变量都是整数 a b c and d是已知的 我如何找到整体解决方案x and y 如果我的想法是正确的 将会有无限多个解 由最小公倍数分隔b and d 但我只需要一个解决方案 我可以计算其余的 这是一个例
  • C# 列表通用扩展方法与非通用扩展方法

    这是一个简单的问题 我希望 集合类中有通用和非通用方法 例如List
  • 两个静态变量同名(两个不同的文件),并在任何其他文件中 extern 其中一个

    在一个文件中将变量声明为 static 并在另一个文件中进行 extern 声明 我认为这会在链接时出现错误 因为 extern 变量不会在任何对象中看到 因为在其他文件中声明的变量带有限定符 static 但不知何故 链接器 瑞萨 没有显
  • 如何定义一个可结构化绑定的对象的概念?

    我想定义一个concept可以检测类型是否T can be 结构化绑定 or not template
  • x:将 ViewModel 方法绑定到 DataTemplate 内的事件

    我基本上问同样的问题这个人 https stackoverflow com questions 10752448 binding to viewmodels property from a template 但在较新的背景下x Bind V
  • 为什么 C# 2.0 之后没有 ISO 或 ECMA 标准化?

    我已经开始学习 C 并正在寻找标准规范 但发现大于 2 0 的 C 版本并未由 ISO 或 ECMA 标准化 或者是我从 Wikipedia 收集到的 这有什么原因吗 因为编写 审查 验证 发布 处理反馈 修订 重新发布等复杂的规范文档需要
  • C 函数 time() 如何处理秒的小数部分?

    The time 函数将返回自 1970 年以来的秒数 我想知道它如何对返回的秒数进行舍入 例如 对于100 4s 它会返回100还是101 有明确的定义吗 ISO C标准没有说太多 它只说time 回报 该实现对当前日历时间的最佳近似 结
  • 使用特定参数从 SQL 数据库填充组合框

    我在使用参数从 sql server 获取特定值时遇到问题 任何人都可以解释一下为什么它在 winfom 上工作但在 wpf 上不起作用以及我如何修复它 我的代码 private void UpdateItems COMBOBOX1 Ite
  • 为什么C++代码执行速度比java慢?

    我最近用 Java 编写了一个计算密集型算法 然后将其翻译为 C 令我惊讶的是 C 的执行速度要慢得多 我现在已经编写了一个更短的 Java 测试程序和一个相应的 C 程序 见下文 我的原始代码具有大量数组访问功能 测试代码也是如此 C 的
  • MySQL Connector C/C API - 使用特殊字符进行查询

    我是一个 C 程序 我有一个接受域名参数的函数 void db domains query char name 使用 mysql query 我测试数据库中是否存在域名 如果不是这种情况 我插入新域名 char query 400 spri
  • 现代编译器是否优化乘以 1 和 -1

    如果我写 template
  • 使用 WGL 创建现代 OpenGL 上下文?

    我正在尝试使用 Windows 函数创建 OpenGL 上下文 现代版本 基本上代码就是 创建窗口类 注册班级 创建一个窗口 choose PIXELFORMATDESCRIPTOR并设置它 创建旧版 OpenGL 上下文 使上下文成为当前

随机推荐