2015-04-23 51 views
2

我有一個在後端使用RavenDB的Web應用程序,並允許用戶跟蹤庫存。這三個實體在我的領域是:如何在RavenDB中做交叉連接/笛卡爾產品?

public class Location 
{ 
    string Id 
    string Name 
} 

public class ItemType 
{ 
    string Id 
    string Name 
} 

public class Item 
{ 
    string Id 
    DenormalizedRef<Location> Location 
    DenormalizedRef<ItemType> ItemType 
} 

在我的web應用程序,有一個頁面,用戶可以看到他們在各個位置上的庫存摘要擊穿。具體來說,它顯示位置名稱,項目類型名稱,然後顯示項目的數量。

我真是第一種方法的地圖/減少對InventoryItems指數:

this.Map = inventoryItems => 
    from inventoryItem in inventoryItems 
    select new 
    { 
     LocationName = inventoryItem.Location.Name, 
     ItemTypeName = inventoryItem.ItemType.Name, 
     Count = 1 
    }); 

this.Reduce = indexEntries => 
    from indexEntry in indexEntries 
    group indexEntry by new 
    { 
     indexEntry.LocationName, 
     indexEntry.ItemTypeName, 
    } into g 
    select new 
    { 
     g.Key.LocationName, 
     g.Key.ItemTypeName, 
     Count = g.Sum(entry => entry.Count), 
    }; 

即工作正常,但它僅顯示有項目的非零計數位置/ ItemType的雙行。我需要讓它顯示全部位置和每個位置的所有項目類型,即使那些沒有任何項目關聯的項目類型。

我已經嘗試了幾種不同的方法,但目前爲止沒有成功。我的想法是將上述內容轉換爲Multi-Map/Reduce索引,然後添加另一個地圖,該地圖可以爲我提供位置和ItemTypes的笛卡爾積,但計數爲0.然後,我可以將它放入縮小圖中並始終每個位置/項目類型對的記錄。

this.AddMap<object>(docs => 
    from itemType in docs.WhereEntityIs<ItemType>("ItemTypes") 
    from location in docs.WhereEntityIs<Location>("Locations") 
    select new 
    { 
     LocationName = location.Name, 
     ItemTypeName = itemType.Name, 
     Count = 0 
    }); 

這不是工作,所以我想RavenDB不喜歡這種映射。有沒有辦法從RavenDB獲得交叉連接/笛卡爾產品?或者,任何其他方式來完成我想要做的事情?

編輯:澄清,地點,ItemTypes和項目是應用程序的用戶創建系統中的文檔。如果系統中沒有任何項目,如果用戶輸入三個位置「倫敦」,「巴黎」和「柏林」以及兩個ItemTypes「桌面」和「筆記本電腦」,預期結果是,當他們查看清單摘要時,他們看到一個表像這樣:

| Location | Item Type | Count | 
|----------|-----------|-------| 
| London | Desktop | 0  | 
| London | Laptop | 0  | 
| Paris | Desktop | 0  | 
| Paris | Laptop | 0  | 
| Berlin | Desktop | 0  | 
| Berlin | Laptop | 0  | 
+0

問題是,你想要的是_all_位置越過所有的類型,對吧? 問題是我們可以按位置或按類型給它,但將它們結合會導致問題。你可以先按位置做,然後按類型? –

+0

@AyendeRahien你是對的,我需要所有類型的所有位置。該請求進入,因爲最終用戶無法看到他們在特定位置「缺貨」的物品。我一直在閱讀關於RavenDB Google Group的更多內容,並且由於「默認安全」的思路,我看到一些關於笛卡爾產品並沒有得到支持的討論。就我而言,我們正在談論幾十個地點,可能有一千種不同的類型,因此索引條目的數量並不是很可笑。我不確定你的意思是「先按位置再按類型先做」。 –

+0

@DavidArcher我有一些相同的挑戰。你有沒有解決這個問題?如果是這樣,你能不能提供最終的索引。 –

回答

0

這裏是你如何能與所有的空位置也這麼做:

AddMap<InventoryItem>(inventoryItems => 
    from inventoryItem in inventoryItems 
    select new 
    { 
     LocationName = inventoryItem.Location.Name, 
     Items = new[]{ 
      { 
       ItemTypeName = inventoryItem.ItemType.Name, 
       Count = 1} 
      } 
    }); 
) 

this.AddMap<Location>(locations=> 
    from location in locations 
    select new 
    { 
     LocationName = location.Name, 
     Items = new object[0] 
    }); 


this.Reduce = results => 
    from result in results 
    group result by result.LocationName into g 
    select new 
    { 
     LocationName = g.Key, 
     Items = from item in g.SelectMany(x=>x.Items) 
       group item by item.ItemTypeName into gi 
       select new 
       { 
        ItemTypeName = gi.Key, 
        Count = gi.Sum(x=>x.Count) 
       } 

    }; 
+0

我不認爲這解決了我的問題。我編輯了原始問題以添加更明確的示例,但基本上,即使系統中完全沒有InventoryItem文檔,我也需要獲得結果。如果用戶只創建一些位置和ItemTypes,但沒有輸入任何實際的InventoryItems,則您發佈的索引中的第一個地圖不會提供任何結果,第二個地圖只會爲每個位置提供一條記錄。 –