问题描述
我们的集合中具有以下文档结构:
{
Title: "Some product",Prices:[{
Currency: "GBP",Value: 10
},{
Currency: "USD",Value: 15
}
]
}
我们正尝试使用C#BSON驱动程序根据特定货币的价格订购这些文档:
sort = Builders<ProductSearchData>.sort.Ascending(x => x.Prices.First(x=>x.Currency == currency).Value);
然后将其传递给集合:
var results = await Collection.FindAsync(filter,new FindOptions<ProductSearchData>
{
Sort = sort,Skip = page*pageSize,Limit = pageSize
});
但是,这没有给出正确的排序顺序。相反,值似乎随机返回。以上语法是正确的还是我们应该以其他方式查询?
如果我们进行更简单的排序,例如
sort = Builders<ProductSearchData>.sort.Descending(x => x.Title);
一切正常。
"{ "find" : "ProductSearch","filter" : { "Prices" : { "$elemmatch" : { "Currency" : 10,"Value" : { "$gte" : 0,"$lte" : 10000 } } },"IsActive" : true },"sort" : { "Value" : 1 },"skip" : 0,"limit" : 10,"$db" : "MyForest_Data","lsid" : { "id" : CSUUID("d4caa989-9493-41a7-bcde-81f198beda7a") } }"
{ "aggregate" : "ProductSearch","pipeline" : [{ "$match" : { "Prices" : { "$elemmatch" : { "Currency" : 10,"IsActive" : true } },{ "$group" : { "_id" : 1,"n" : { "$sum" : 1 } } }],"cursor" : { },"lsid" : { "id" : CSUUID("d4caa989-9493-41a7-bcde-81f198beda7a") } }
解决方法
并不是解决问题的真正答案,而是对发生的情况的解释:
到达数据库的查询是
"find" : "ProductSearch","filter" : {
"Prices" : {
"$elemMatch" : {
"Currency" : 10,"Value" : { "$gte" : 0,"$lte" : 10000 }
}
},"IsActive" : true
},"sort" : { "Value" : 1 },"skip" : 0,"limit" : 10,
它将搜索价格在0到10,000之间的特定货币的文档,然后按顶级字段Value
进行排序。我的猜测不是OP想要的,根本没有这样的字段,因此文档以自然顺序返回。
快速搜索会带来MongoDB find subdocument and sort the results,这似乎是对匹配的子文档进行排序的合理方法。
,怎么样:
collection.AsQueryable()
.SelectMany(x => x.Prices,(x,pr) => new { T = x.Title,V = pr.Value,C = pr.Currency } )
.Where(x => x.C == "GBP")
.OrderBy(x => x.V)
.Skip(0)
.Take(100)
- 跳过并进行分页...
我调查了其他两个答案的建议,但是找不到一种干净的方法来执行UnWind命令,该命令允许我们在MongoDB C#库中使用Builders。此外,在反思时,我们担心MongoDB的性能影响必须对每个查询执行内存释放。
相反,我们决定在建立索引过程中“放松”“价格”字段。当我们将产品编入搜索集合中时,我们会为产品具有的每种货币创建一个记录。我们还设置了一个组ID,该ID允许我们标识所有相关记录以进行清理:
var results = new IndexingData();
results.GroupId = source.Id.ToString();
foreach (var price in source.Prices)
{
var searchData = new ProductSearchRecord()
{
Id= $"{source.Id}{price.Currency}",GroupId = source.Id.ToString(),Title = source.Title,Price= price,};
results.Records.Add(searchData);
}
return results;
插入集合:
var indexingData = GetRecords(source);
await Collection.DeleteManyAsync(x => x.GroupId == indexingData.GroupId);
foreach (var record in indexingData.Records)
{
await Collection.ReplaceOneAsync(x => x.Id == record.Id,record,new UpdateOptions() {IsUpsert = true});
}