C# RavenDb中的Map reduce超过2个集合和子集合

C# RavenDb中的Map reduce超过2个集合和子集合,c#,mapreduce,ravendb,C#,Mapreduce,Ravendb,我在RavenDb中存储了两种不同的对象类型,它们是父/子类型关系,如JSON中所示: Account/1 { "Name": "Acc1", } Items/1 { "Account": "Account/1", "Value" : "100", "Tags": [ "tag1", "tag2"] } Items/2 { "Account": "Account/1", "Value" : "50",

我在RavenDb中存储了两种不同的对象类型,它们是父/子类型关系,如JSON中所示:

Account/1
{        
    "Name": "Acc1",
}

Items/1
{
    "Account": "Account/1",
    "Value" : "100",
    "Tags": [
       "tag1",
       "tag2"]
}

Items/2
{
    "Account": "Account/1",
    "Value" : "50",
    "Tags": [
       "tag2"]
}
请注意,我不想将它们存储在同一个文档中,因为一个帐户可能有数千项

我正在尝试编写一个map/reduce索引,该索引将返回以下内容:

{
    "Account": "Acc1",
    "TagInfo": [
        { "TagName" : "tag1",
          "Count" : "1",  //Count of all the "tag1" occurrences for acc1
          "Value" : "100" //Sum of all the Values for acc1 which are tagged 'tag1'
        },
        { "TagName" : "tag2",
          "Count" : "2",  //Two items are tagged "tag2"
          "Value" : "150"
        }]
}
i、 e.所有不同标记名的列表,以及每个标记名的编号及其值

我想我需要使用多重映射来将帐户和项目集合映射到一起,但我无法找出reduce部分来创建结果的“TagInfo”部分

这是可能的,还是我在Raven中的建模都错了

编辑:

我希望从此查询中检索的类如下所示:

public class QueryResult
{
    public string AccountId {get;set;}
    public TagInfo Tags {get;set;} 
}

public class TagInfo
{
    public string TagName {get;set;}
    public int Count {get;set;}
    public int TotalSum {get;set;}
}
var results = session.Query<TagsWithCountAndValues.ReduceResult, TagsWithCountAndValues>()
    .Where(x => x.AccountId == "accounts/1")                        
    .ToList();

您不能为此使用多重映射/减少索引,因为您希望标记上有一个映射,而帐户上有另一个映射。它们没有公共属性,因此这里不能有多重贴图/减少

但是,您可以改用TransformResult。以下是如何做到这一点:

public class Account
{
    public string Id { get; set; }
    public string Name { get; set; }
}

public class Item
{
    public string Id { get; set; }
    public string AccountId { get; set; }
    public int Value { get; set; }
    public List<string> Tags { get; set; }
}

public class TagsWithCountAndValues : AbstractIndexCreationTask<Item, TagsWithCountAndValues.ReduceResult>
{
    public class ReduceResult
    {
        public string AccountId { get; set; }
        public string AccountName { get; set; }
        public string Tag { get; set; }
        public int Count { get; set; }
        public int TotalSum { get; set; }
    }

    public TagsWithCountAndValues()
    {
        Map = items => from item in items
                        from tag in item.Tags
                        select new
                        {
                            AccountId = item.AccountId,
                            Tag = tag,
                            Count = 1,
                            TotalSum = item.Value
                        };
        Reduce = results => from result in results
                            group result by result.Tag
                            into g
                            select new
                            {
                                AccountId = g.Select(x => x.AccountId).FirstOrDefault(),
                                Tag = g.Key,
                                Count = g.Sum(x => x.Count),
                                TotalSum = g.Sum(x => x.TotalSum)
                            };
        TransformResults = (database, results) => from result in results
                                                    let account = database.Load<Account>(result.AccountId)
                                                    select new
                                                    {
                                                        AccountId = result.AccountId,
                                                        AccountName = account.Name,
                                                        Tag = result.Tag,
                                                        Count = result.Count,
                                                        TotalSum = result.TotalSum
                                                    };
    }
}
公共类帐户
{
公共字符串Id{get;set;}
公共字符串名称{get;set;}
}
公共类项目
{
公共字符串Id{get;set;}
公共字符串AccountId{get;set;}
公共int值{get;set;}
公共列表标记{get;set;}
}
带有countandvalues的公共类标记:AbstractIndexCreationTask
{
公共类ReduceResult
{
公共字符串AccountId{get;set;}
公共字符串AccountName{get;set;}
公共字符串标记{get;set;}
公共整数计数{get;set;}
公共整数总和{get;set;}
}
公共标记swithCountAndValues()
{
Map=items=>来自items中的item
从item.Tags中的标记
选择新的
{
AccountId=项目。AccountId,
标签=标签,
计数=1,
TotalSum=项目价值
};
Reduce=results=>from result in results
按result.Tag对结果进行分组
进入g
选择新的
{
AccountId=g.Select(x=>x.AccountId).FirstOrDefault(),
标记=g.键,
Count=g.Sum(x=>x.Count),
TotalSum=g.Sum(x=>x.TotalSum)
};
TransformResults=(数据库,结果)=>来自结果中的结果
让account=database.Load(result.AccountId)
选择新的
{
AccountId=result.AccountId,
AccountName=account.Name,
Tag=result.Tag,
计数=结果。计数,
TotalSum=结果。TotalSum
};
}
}
然后,您可以这样查询:

public class QueryResult
{
    public string AccountId {get;set;}
    public TagInfo Tags {get;set;} 
}

public class TagInfo
{
    public string TagName {get;set;}
    public int Count {get;set;}
    public int TotalSum {get;set;}
}
var results = session.Query<TagsWithCountAndValues.ReduceResult, TagsWithCountAndValues>()
    .Where(x => x.AccountId == "accounts/1")                        
    .ToList();
var results=session.Query()
。其中(x=>x.AccountId==“accounts/1”)
.ToList();

好的,我找到了一种可以接受的方法,以丹尼尔的答案为基础,在这里记录下来,供未来的旅行者(可能是我自己!)

我从尝试每个帐户返回一个结果更改为每个帐户/标记组合返回一个结果,因此索引必须更改如下(注意
reduce
中的
groupby
位于2个属性上):


这给了我们每个帐户一个对象,以及
TagInfo
对象的子列表-每个唯一标记一个对象。

谢谢Daniel,我不知道
TransformResults
!但这并不是我想要的,我希望每个帐户都有一个结果,属性包含标记详细信息,请参见我的编辑。此外,上面的TotalSum不起作用,因为它对所有项目值进行求和,而不仅仅是我查询的帐户的值(我认为reduce需要按帐户分组,而不是标记?),您不能在其结果中有嵌套类的索引。我不认为你能在一个索引中得到你想要的。相反,我更希望有一些独立的索引并查询它们,以获得所需的所有信息,或者更改数据模型,使其更好地适合这种数据访问模式。好的,谢谢Daniel。我想可能是这样,但不太确定。非常感谢您抽出时间。
var hierachicalResult = from result in results
                        group new {result.TagName, result.TagValue} by result.AccountName
                        into g
                        select new
                        {
                            Account = g.Key,
                            TagInfo = g.Select(x => new { x.TagName, x.TagValue, x.TagCount })
                        };