HaB*_*aBo 1 mongodb mongodb-.net-driver
如何使用 MongoDB-Csharp 驱动程序编写以下查询
SELECT SubSet.*
FROM ( SELECT T.ProductName ,
T.Price ,
ROW_NUMBER() OVER ( PARTITION BY T.ProductName ORDER BY T.ProductName ) AS ProductRepeat
FROM myTable T
) SubSet
WHERE SubSet.ProductRepeat = 1
Run Code Online (Sandbox Code Playgroud)
我想要实现的是
收藏
预期结果是
这是一次尝试(请不要使用对象和字段)
public List<ProductOL> Search(ProductOL obj, bool topOneOnly)
{
List<ProdutOL> products = new List<ProductOL>();
var database = MyMongoClient.Instance.OpenToRead(dbName: ConfigurationManager.AppSettings["MongoDBDefaultDB"]);
var collection = database.GetCollection<RawBsonDocument>("Products");
List<IMongoQuery> build = new List<IMongoQuery>();
if (!string.IsNullOrEmpty(obj.ProductName))
{
var ProductNameQuery = Query.Matches("ProductName", new BsonRegularExpression(obj.ProductName, "i"));
build.Add(ProductNameQuery);
}
if (!string.IsNullOrEmpty(obj.BrandName))
{
var brandNameQuery = Query.Matches("BrandName", new BsonRegularExpression(obj.BrandName, "i"));
build.Add(brandNameQuery);
}
var fullQuery = Query.And(build.ToArray());
products = collection.FindAs<ProductOL>(fullQuery).SetSortOrder(SortBy.Ascending("ProductName")).ToList();
if (topOneOnly)
{
var tmpProducts = new List<ProductOL>();
foreach (var item in products)
{
if (tmpProducts.Any(x => x.ProductName== item.ProductName)) { }
else
tmpProducts.Add(item);
}
products = tmpProducts;
}
return products;
}
Run Code Online (Sandbox Code Playgroud)
我的 mongo 查询有效并给出了正确的结果。但是当我处理大量数据时,这并不有效,所以我想知道 mongodb 是否有任何像 SQL Server for Row_Number() 和分区这样的概念
如果您的查询返回预期结果但效率不高,您应该使用以下命令查看索引使用情况explain()
. 鉴于您的查询生成代码包含条件子句,您似乎可能需要多个索引来有效地覆盖常见变化。
我不确定您提供的 C# 代码与原始 SQL 查询有何关系,因为它们似乎完全不同。除了限制返回的结果之外,我也不清楚分组将如何帮助您的查询性能。
MongoDB 中没有直接等效的ROW_NUMBER() .. PARTITION BY
分组,但您应该能够使用聚合框架(最快)或Map/Reduce(速度较慢但功能更多)计算出所需的结果。MongoDB 手册包含聚合命令比较以及使用示例。
作为翻译练习,我将重点关注您的 SQL 查询,该查询将按 ProductName 提取第一个产品匹配项:
SELECT SubSet.* FROM ( SELECT T.ProductName , T.Price , ROW_NUMBER() OVER ( PARTITION BY T.ProductName ORDER BY T.ProductName ) AS ProductRepeat FROM myTable T ) SubSet WHERE SubSet.ProductRepeat = 1
设置您提供的测试数据:
db.myTable.insert([
{ ProductName: 'Cap', Price: 10, SKU: 'AB123' },
{ ProductName: 'Bag', Price: 5, SKU: 'ED567' },
{ ProductName: 'Cap', Price: 20, SKU: 'CD345' },
{ ProductName: 'Cap', Price: 5, SKU: 'EC123' },
])
Run Code Online (Sandbox Code Playgroud)
这是 shell 中的聚合查询mongo
,它将找到每个组的第一个匹配项(按 ProductName 排序)。MongoCollection.Aggregate()
使用方法将该聚合查询转换为 C# 驱动程序应该很简单。
我已在您的原始查询中包含了粗略等效 SQL 片段的注释。
db.myTable.aggregate(
// Apply a sort order so the $first product is somewhat predictable
// ( "ORDER BY T.ProductName")
{ $sort: {
ProductName: 1
// Should really have additional sort by Price or SKU (otherwise order may change)
}},
// Group by Product Name
// (" PARTITION BY T.ProductName")
{ $group: {
_id: "$ProductName",
// Find first matching product details per group (can use $$CURRENT in MongoDB 2.6 or list specific fields)
// "SELECT SubSet.* ... WHERE SubSet.ProductRepeat = 1"
Price: { $first: "$Price" },
SKU: { $first: "$SKU" },
}},
// Rename _id to match expected results
{ $project: {
_id: 0,
ProductName: "$_id",
Price: 1,
SKU: 1,
}}
)
Run Code Online (Sandbox Code Playgroud)
给出的测试数据的结果似乎是您正在寻找的:
{ "Price" : 10, "SKU" : "AB123", "ProductName" : "Cap" }
{ "Price" : 5, "SKU" : "ED567", "ProductName" : "Bag" }
Run Code Online (Sandbox Code Playgroud)
笔记:
$first
运算符,因此如果您想查找每个分组的第二个或第三个产品,您需要采用不同的方法(例如,$group
然后获取应用程序代码中所需的结果子集)$group
,则应该有更具体的排序标准ProductName
(例如,按ProductName
&Price
或ProductName
&排序SKU
)。否则,随着文档的添加或更新,结果的顺序将来可能会发生变化。 归档时间: |
|
查看次数: |
2257 次 |
最近记录: |