mapreduce - How to do a cross join / cartesian product in RavenDB? -
i have web application uses ravendb on backend , allows user keep track of inventory. 3 entities in 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 }
on web app, there page user see summary breakdown of inventory have @ various locations. specifically, shows location name, item type name, , count of items.
the first approach took map/reduce index on inventoryitems:
this.map = inventoryitems => inventoryitem in inventoryitems select new { locationname = inventoryitem.location.name, itemtypename = inventoryitem.itemtype.name, count = 1 }); this.reduce = indexentries => indexentry in indexentries group indexentry new { indexentry.locationname, indexentry.itemtypename, } g select new { g.key.locationname, g.key.itemtypename, count = g.sum(entry => entry.count), };
that working fine displays rows location/itemtype pairs have non-zero count of items. need have show all locations , each location, item types don't have items associated them.
i've tried few different approaches no success far. thought turn above multi-map/reduce index , add map give me cartesian product of locations , itemtypes count of 0. feed reduce , have record every location/itemtype pair.
this.addmap<object>(docs => itemtype in docs.whereentityis<itemtype>("itemtypes") location in docs.whereentityis<location>("locations") select new { locationname = location.name, itemtypename = itemtype.name, count = 0 });
this isn't working though i'm thinking ravendb doesn't kind of mapping. there way cross join / cartesian product ravendb? alternatively, other way accomplish i'm trying do?
edit: clarify, locations, itemtypes, , items documents in system user of app creates. without items in system, if user enters 3 locations "london", "paris", , "berlin" along 2 itemtypes "desktop" , "laptop", expected result when @ inventory summary, see table so:
| location | item type | count | |----------|-----------|-------| | london | desktop | 0 | | london | laptop | 0 | | paris | desktop | 0 | | paris | laptop | 0 | | berlin | desktop | 0 | | berlin | laptop | 0 |
here how can empty locations well:
addmap<inventoryitem>(inventoryitems => inventoryitem in inventoryitems select new { locationname = inventoryitem.location.name, items = new[]{ { itemtypename = inventoryitem.itemtype.name, count = 1} } }); ) this.addmap<location>(locations=> location in locations select new { locationname = location.name, items = new object[0] }); this.reduce = results => result in results group result result.locationname g select new { locationname = g.key, items = item in g.selectmany(x=>x.items) group item item.itemtypename gi select new { itemtypename = gi.key, count = gi.sum(x=>x.count) } };