2

Say I have following data structure:

{
"_id" : LUUID("d14c526e-34ba-4c41-9bb0-3bc32d9de106"),
"Address" : {
    "Street" : "Winner street",
    "HouseNo" : "776",
    "PostalCode" : 9619,
    "City" : "Majestic"
},
"Sales" : {
    "Price" : 1315000,
    "Submitted" : ISODate("2013-07-31T16:30:00Z"),
    "SaleChanges" : [ 
        {
            "ChangeDate" : ISODate("2013-08-01T14:40:18Z"),
            "Price" : 1795000
        },
        {
            "ChangeDate" : ISODate("2013-08-03T14:40:18Z"),
            "Price" : 1340000
        }
    ]
}

}

And I need to find price decreases for "SaleChanges" for some period of time.

Now I'm using C# driver for mongodb, linq based query and some C# extensions methods:

internal static bool HasPriceDecreasesInLastSpan(this SaleModel sales, TimeSpan span, DateTime from)
    {
        var date = from;
        var dateSpanBefore = date.Subtract(span);
        var salesHistory = new List<PreviousSaleModel>();

        var lastSale = sales.SaleChanges.OrderByDescending(s => s.ChangeDate).FirstOrDefault();
        if (lastSale != null)
        {
            salesHistory.Add(new PreviousSaleModel()
            {
                ChangeDate = lastSale.ChangeDate,
                Price = sales.Price
            });
        }
        salesHistory.AddRange(sales.SaleChanges.Where((sc => sc.ChangeDate >= dateSpanBefore && sc.ChangeDate <= from)));

        return salesHistory.HasPriceDecreases();
    }

internal static bool HasPriceDecreases(this IEnumerable<PreviousSaleModel> salesHistory)
    {
        using (var e = salesHistory.OrderByDescending(key => key.ChangeDate).GetEnumerator())
        {
            var buffer = new List<PreviousSaleModel>();
            while (e.MoveNext())
            {
                foreach (var item in buffer)
                {
                    if (item.Price < e.Current.Price)
                        return true;
                }
                buffer.Add(e.Current);
            }
        }

        return false;
    }

var predicate = new Func<UnitModel, bool>(bm => bm.Sales != null && bm.Sales.SaleChanges.Count > 0 && bm.Sales.HasPriceDecreasesInLastNDays(days, fromDate));
        _query = _query.Where(predicate).AsQueryable();

Main problem with this solution is performance lost. Mongo should look inside every record to make computations. Is there alternatives to this?

4

1 回答 1

0

如果您需要查询 price 和 salesChange.price 之间的差异,我建议将计算值与数组中的每个项目一起存储。只需在每次插入和更新之前设置它。您有几个选项可以在查询中获取类似的计算值,但无论如何都会很慢。如果这是您需要经常做的事情,只需在插入之前设置它并在其上创建索引。

在更传统的数据库中受过教育的人会对随意对数据进行非规范化的想法感到畏缩,但 Mongo 不是关系数据库,它是基于 Documents 的。通常,您可以随意对文档中的数据进行非规范化处理,因为通常整个文档总是自动更新,因此最终得到无效数据的风险不同。

于 2014-02-06T19:13:57.567 回答