2013-08-05 91 views
2

元素MongoDB的複雜查詢說我有下面的數據結構:匹配陣列和性能

{ 
"_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 
     } 
    ] 
} 

}

,我需要找到「SaleChanges」了一段時間的價格下降。

現在,我使用MongoDB的C#驅動程序,基於LINQ查詢和一些C#擴展方法:

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(); 

與此解決方案的主要問題是性能丟失。 Mongo應該查看每條記錄進行計算。有沒有其他辦法呢?

+0

您可以設計數據庫以保存額外信息,例如更改之間的價格差異。但是對於當前的設計,您可以使用低效的查詢(不使用索引):'db.collection.find({$ where:「this.SaleChanges [1] randunel

+0

您可能可以使用聚合建立您的請求。你嘗試過嗎?從C#語法上來看,它不是很好,但性能應該好得多(假設你可以使用聚合來工作)。 – WiredPrairie

回答

0

如果您需要查詢價格和salesChange.price之間的差異,我建議將計算值與數組中的每個項目一起存儲。只需在每次插入和更新之前設置它。你有幾個選項可以在查詢中獲得類似的計算值,但是它會以任何方式變慢。如果這是您需要經常執行的操作,只需在插入它之前進行設置並在其上創建索引即可。

在更傳統的數據庫中受過教育的人會對你的數據非規範化的想法產生畏懼,但Mongo不是關係型數據庫,它基於Documents。一般來說,您可以隨意在文檔中對數據進行非規範化處理,因爲通常整個文檔總是以原子方式更新,因此與結束處理無效數據的風險並不相同。