正如例外中所述,在 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 个选择:
- 看看最新的LINQ3执行 https://mongodb.github.io/mongo-csharp-driver/2.14/reference/driver/crud/linq3/。我知道与 LINQ2(默认)相比,它支持 LINQ 查询中的更多不同情况,但我没有这方面的经验,因此需要更多调查。
- 您可以查看您的目标是否可以使用 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:
-
看起来像$substract
LINQ2 支持:
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 个运算符支持它:
-
Example https://docs.mongodb.com/manual/reference/operator/aggregation/subtract/#subtract-milliseconds-from-a-date如何从数据中提取毫秒
$substact
.
- 你可以看看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
}
}
]
}