2

假设我有一个典型的客户和订单场景。我有一个客户集合,每个客户文档都有一个订单列表。现在我要查询订单日期在上周的客户,即大于DateTime.UtcNow.AddDays(-7),小于DateTime.UtcNow。

var startDate = DateTime.UtcNow.AddDays(-7);
var endDate = DateTime.UtcNow;
var query = collection.AsQueryable<Customer>()
    .Where(c => c.Orders.Any(o => o.OrderDate > startDate && o.OrderDate < endDate))
    .SelectMany(b => b.Orders);

这会导致以下错误:

System.NotSupportedException: The SelectMany query operator is not supported.
at MongoDB.Driver.Linq.SelectQuery.TranslateMethodCall(MethodCallExpression methodCallExpression) in C:\\build\\mongo-csharp-driver\\Driver\\Linq\\Translators\\SelectQuery.cs:line 687

我目前的解决方案非常讨厌:

var customers =
    collection.AsQueryable<Customer>()
        .Where(c => 
            c.Orders.Any(o => 
                o.OrderDate > startDate && 
                o.OrderDate < endDate))
        .ToList();

var results = new List<Order>();
foreach (var orders in customer.Select(c => 
    c.Orders.Where(o => 
        o.OrderDate > startDate && 
        o.OrderDate < endDate)))
{
    results.AddRange(orders);
}

return results;

有没有更好的方法来实现这一目标?

4

1 回答 1

1

作为一个几乎一般的规则,我不会在客户中嵌入订单。在不获取他们曾经下过的所有订单的情况下找到所有客户似乎是一个非常自然的查询。此外,订单通常具有相当复杂的生命周期并代表长期运行的业务交易,因此它们值得单独记录。

当然,这在一定程度上取决于您的确切要求,但客户是如此重要,以至于您可以争辩嵌入付款、查询、取消、发票以及基本上任何其他以某种方式与客户相关的业务交易,所以您最终将所有数据填充到一个无法管理的集合中。

无论如何,查询db.Orders.find({"OrderDate" : {$gt : lastWeek} });然后使用$in运营商通过Order.CustomerId.

如果上周的订单数量很大(比如 > 10,000),那么MostRecentOrder在客户中引入一个字段或使用 map/reduce 来代替是有意义的。也可以对订单进行分页,然后$in对生成的较小大小的块使用运算符。如果您这样做,请确保按照一些稳定的标准进行排序,例如OrderDate.

于 2013-03-21T15:23:58.520 回答