2015-04-23 69 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,则您发布的索引中的第一个地图不会提供任何结果,第二个地图只会为每个位置提供一条记录。 –