如何在RavenDB中进行交叉联接/笛卡尔积? [英] How to do a cross join / cartesian product in RavenDB?

查看:76
本文介绍了如何在RavenDB中进行交叉联接/笛卡尔积?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Web应用程序,该应用程序在后端使用RavenDB并允许用户跟踪库存.我域中的三个实体是:

I have a web application that uses RavenDB on the backend and allows the user to keep track of inventory. The three entities in my domain are:

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应用程序上,有一个页面供用户查看其在各个位置的库存的摘要分类.具体来说,它显示位置名称,项目类型名称,然后显示项目计数.

On my web app, there is a page for the user to see a summary breakdown of the inventory they have at the various locations. Specifically, it shows the location name, item type name, and then a count of items.

我采用的第一种方法是在InventoryItems上使用map/reduce索引:

The first approach I took was a map/reduce index on 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),
    };

这很好,但是它只显示具有非零项计数的Location/ItemType对的行.我需要让它显示 all 位置,并且对于每个位置,所有项目类型,甚至是那些没有任何与之关联的项目.

That is working fine but it only displays rows for Location/ItemType pairs that have a non-zero count of items. I need to have it show all Locations and for each location, all item types even those that don't have any items associated with them.

我尝试了几种不同的方法,但到目前为止没有成功.我的想法是将以上内容转换为Multi-Map/Reduce索引,然后添加另一个映射,该映射将为我提供Locations和ItemTypes的笛卡尔积,但计数为0.然后,我可以将其输入reduce中并始终具有每个位置/项目类型对的记录.

I've tried a few different approaches but no success so far. My thought was to turn the above into a Multi-Map/Reduce index and just add another map that would give me the cartesian product of Locations and ItemTypes but with a Count of 0. Then I could feed that into the reduce and would always have a record for every location/itemtype pair.

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获得交叉联接/笛卡尔积?另外,还有其他方法可以完成我想做的事情吗?

This isn't working though so I'm thinking RavenDB doesn't like this kind of mapping. Is there a way to get a cross join / cartesian product from RavenDB? Alternatively, any other way to accomplish what I'm trying to do?

为明确起见,位置,项目类型和项目是应用程序用户创建的系统中的文档.在系统中没有任何商品的情况下,如果用户输入三个位置伦敦",巴黎"和柏林"以及两个商品类型桌面"和笔记本电脑",则预期结果是当他们查看库存摘要时,他们看到这样的表格:

To clarify, Locations, ItemTypes, and Items are documents in the system that the user of the app creates. Without any Items in the system, if the user enters three Locations "London", "Paris", and "Berlin" along with two ItemTypes "Desktop" and "Laptop", the expected result is that when they look at the inventory summary, they see a table like so:

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

推荐答案

以下是您也可以在所有空白位置执行此操作的方法:

Here is how you can do this with all the empty locations as well:

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)
                }

    };

这篇关于如何在RavenDB中进行交叉联接/笛卡尔积?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆