c# - 如何使用 C#、LINQ 在 mongodb 中获取每个组的 n 条记录?
问题描述
每组需要得到10个项目。按 ID 降序和按类别分组
public class Item
{
public string Id { get; set ; }
public string Name { get ; set ; }
public string Category { get ; set ; }
}
我尝试过这样的事情。
var data = Collection.AsQueryable()
.OrderByDescending(o=> o.Id)
.GroupBy(x => x.Category)
.Select(g => new { GroupName = g.Key, Items =
g.Take(10).ToList() });
但是遇到了这样的异常
System.NotSupportedException:不支持指定的方法。在 MongoDB.Driver.Linq.Processors.AccumulatorBinder.GetAccumulatorArgument(表达式节点)
解决方案
请改用聚合框架。MongoDB LINQ 提供程序建立在它之上。
您可以Id
使用以下查询按降序排列每个组的 10 个项目:
db.items.aggregate([
{ "$sort": { "Id": -1 } },
{ "$group": { "_id": "$Category", "Items": { "$push": "$$ROOT" } } },
{ "$project": { "_id": 0, "GroupName": "$_id", "Items": { "$slice": ["$Items", 10] } } }
])
C#代码如下:
// models
public class Item
{
public string Id { get; set; }
public string Name { get; set; }
public string Category { get; set; }
}
public class ItemsGroup
{
public string GroupName { get; set; }
public Item[] Items { get; set; }
}
// query
var collection = db.GetCollection<Item>("Items");
IAggregateFluent<ItemsGroup> result = collection.Aggregate()
.SortByDescending(o => o.Id)
.Group(BsonDocument.Parse("{ _id: '$Category', Items: { '$push': '$$ROOT'}}"))
.Project<ItemsGroup>(BsonDocument.Parse("{ _id: 0, GroupName: '$_id', Items: { $slice: ['$Items', 10]}}"));
List<ItemsGroup> groups = result.ToList();
但是,此查询可能有问题。如果每个组有数千个项目,我猜小组赛阶段会将它们全部保存在Items
临时数组中,而我们只需要 10 个。
如果被分组的键的数量不是很大,那么最好为每个组执行 $lookup 而不是将所有内容推入一个数组然后对其进行切片。这可以通过以下查询来实现:
aggregate([
{ "$group": { "_id": "$Category" } },
{ "$lookup": {
"from": "Items",
"let": { "c": "$_id" },
"as": "Items"
"pipeline": [
{ "$match": { "$expr": { "$eq": ["$Category", "$$c"] } } },
{ "$sort": { "Id": -1 } },
{ "$limit": 10 }
],
}
},
{ "$project": { "_id": 0, "GroupName": "$_id", "Items": 1 } }
])
在 C# 代码中,它会像:
BsonArray pipeline = new BsonArray
{
BsonDocument.Parse("{ $match: { $expr: { $eq: ['$Category', '$$c']} } }"),
BsonDocument.Parse("{ $sort: { Id: -1 } }"),
BsonDocument.Parse("{ $limit: 10 }")
};
BsonDocument lookup = new BsonDocument("$lookup",
new BsonDocument("from", "Items")
.Add("let", new BsonDocument("c", "$_id"))
.Add("pipeline", pipeline)
.Add("as", "Items")
);
IAggregateFluent<ItemsGroup> result = collection.Aggregate()
.Group(BsonDocument.Parse("{ _id: '$Category' }"))
.AppendStage<object>(lookup)
.Project<ItemsGroup>("{ _id: 0, GroupName: '$_id', Items: 1 }");
List<ItemsGroup> groups = result.ToList();
推荐阅读
- azure-data-factory - 如何在执行之前获得活动名称
- angular - 如何在角茉莉花规格中模拟路由器
- python - 夏普比率作为 LSTM 中的损失函数
- javascript - 无论如何我可以检查localStorage中的重复项吗
- javascript - 无法使用 Jasmine Spy 覆盖代码
- linux - 安装内核头文件包丢失错误
- javascript - 我怎样才能知道双击(选定)的单词是否在一个范围内
- node.js - 如何让discordbot在不使用discord命令但实时数据的情况下执行命令?
- php - 如何在 CakePHP 3.4 上将 CSRF cookie 设置为相同站点?
- reactjs - 为什么反应上下文中没有显示该值?