Ravendb 如何在单个用户报告中检索多个计数字段?

Ravendb 如何在单个用户报告中检索多个计数字段?,ravendb,Ravendb,假设我有一个User类,如下所示: public class User { public string Id {get; set;} public string Name {get; set;} } 每个用户都可以是导师、学员或两者兼而有之。这由关系类表示: public class Relationship { public string MentorId {get; set;} // This is a User.Id public string MenteeId

假设我有一个
User
类,如下所示:

public class User
{
   public string Id {get; set;}
   public string Name {get; set;}
}
每个用户都可以是导师、学员或两者兼而有之。这由
关系
类表示:

public class Relationship
{
   public string MentorId {get; set;} // This is a User.Id
   public string MenteeId {get; set;} // This is another User.Id
}
现在我想生成一个报告,列出我的所有用户,并包含一个名为
Mentor Count
的字段和另一个名为
Mentee Count
的字段。为了实现这一点,我创建了一个
UserReportDTO
类来保存我的报告数据

public class UserReportDTO
{
   public string Name {get; set;}
   public string MentorCount {get; set;}
   public string MenteeCount {get; set;}
}
然后我查询我的RavenDB以获得所有
用户的列表
,并将其转换为
UserReportDTO
实例的列表

用户服务

public List<UserReportDTO> GetReportChunk(
    IDocumentSession db,
    int skip = 0,
    int take = 1024)
{
    return db.Query<User>()
            .OrderBy(u => u.Id)
            .Skip(skip)
            .Take(take)
            .ToList()
            .Select(user =>
                new UserReportDTO
                {
                    Name = user.Name,
                    MentorCount = // What goes here?
                    MenteeCount = // What goes here?
                })
            .ToList();
}
多地图索引

public class Users_WithRelationships :
        AbstractMultiMapIndexCreationTask<Users_WithRelationships.Result>
{
    public class Result
    {
        public string UserId { get; set; }
        public string[] Claims { get; set; }
        public int MentorCount { get; set; }
        public int MenteeCount { get; set; }
    }

    public Users_WithRelationships()
    {
        AddMap<User>(users => users.Select(user => new
        {
                UserId = user.Id,
                user.Claims,
                MentorCount = 0,
                MenteeCount = 0
        }));

        AddMap<Relationship>(relationships => relationships.Select(relationship => new
        {
                UserId = relationship.MentorId,
                Claims = (string[]) null,
                MentorCount = 0,
                MenteeCount = 1
        }));

        AddMap<Relationship>(relationships => relationships.Select(relationship => new
        {
                UserId = relationship.MenteeId,
                Claims = (string[]) null,
                MentorCount = 1,
                MenteeCount = 0
        }));

        Reduce = results => results.GroupBy(result => result.UserId).Select(g => new
        {
                UserId = g.Key,
                Claims = g.Select(x => x.Claims).FirstOrDefault(x => x != null),
                MentorCount = g.Sum(x => x.MentorCount),
                MenteeCount = g.Sum(x => x.MenteeCount)
        });
    }
}
public类用户\u与关系:
AbstractMultiMapIndexCreationTask
{
公开课成绩
{
公共字符串用户标识{get;set;}
公共字符串[]声明{get;set;}
公共整数计数{get;set;}
公共int-MenteeCount{get;set;}
}
公共用户与关系()
{
AddMap(用户=>users.Select(用户=>new
{
UserId=user.Id,
用户声明,
计数=0,
MenteeCount=0
}));
AddMap(关系=>relationships.Select(关系=>new
{
UserId=relationship.MentorId,
声明=(字符串[])null,
计数=0,
MenteeCount=1
}));
AddMap(关系=>relationships.Select(关系=>new
{
UserId=relationship.MenteeId,
声明=(字符串[])null,
计数=1,
MenteeCount=0
}));
Reduce=results=>results.GroupBy(result=>result.UserId)。选择(g=>new
{
UserId=g.Key,
Claims=g.Select(x=>x.Claims).FirstOrDefault(x=>x!=null),
导师计数=g.Sum(x=>x.MentorCount),
MenteeCount=g.Sum(x=>x.MenteeCount)
});
}
}

如果一个模型已经保存了您与用户的关系数据,您可能会得到更好的服务。这可能看起来像:

公共类用户
{
公共字符串Id{get;set;}
公共字符串名称{get;set;}
公共字符串[]用户标识{get;set;}
公共字符串[]MenteeUserIds{get;set;}
}
但是,如果您想坚持所描述的模型,解决方案是去掉多个单独的索引,创建一个包含所需数据的多映射索引

public类用户\u与关系
:AbstractMultiMapIndexCreationTask
{
公开课成绩
{
公共字符串用户标识{get;set;}
公共字符串名称{get;set;}
公共整数计数{get;set;}
公共int-MenteeCount{get;set;}
}
公共用户与关系()
{
AddMap(用户=>来自用户中的用户
选择新的
{
UserId=user.Id,
Name=user.Name,
计数=0,
MenteeCount=0
});
AddMap(关系=>来自关系中的关系
选择新的
{
UserId=relationship.MentorId,
Name=(字符串)null,
计数=1,
MenteeCount=0
});
AddMap(关系=>来自关系中的关系
选择新的
{
UserId=relationship.MenteeId,
Name=(字符串)null,
计数=0,
MenteeCount=1
});
减少=结果=>
从结果到结果
按result.UserId对结果进行分组
进入g
选择新的
{
UserId=g.Key,
Name=g.Select(x=>x.Name).FirstOrDefault(x=>x!=null),
导师计数=g.Sum(x=>x.MentorCount),
MenteeCount=g.Sum(x=>x.MenteeCount)
};
}
}
然后,如果仍要投影自定义DTO,则可以更新
GetReportChunk
方法,以查询one索引

返回db.Query()
.OrderBy(x=>x.UserId)
.Skip(Skip)
.拿(拿)
.选择(x=>
新UserReportDTO
{
Name=x.Name,
导师人数=x.导师人数,
MenteeCount=x.MenteeCount,
})
.ToList();

你会在下一场比赛中击败我。:)@马特·约翰逊——谢谢。请参阅问题中的编辑1。您在报告时期望完成的工作太多。如果.GetRegistrationWorkflow()需要用户提供其他字段,那么您应该在工作流的前面运行此逻辑,并保存结果,以便更容易查询。如果它完全基于输入声明,那么您不需要实现完整的用户,是吗?好的,现在全部排序。您的
AbstractMultiMapIndexCreationTask
是关键。为了完整起见,我将工作查询和投影放在上面的edit1中。
public class Users_WithRelationships :
        AbstractMultiMapIndexCreationTask<Users_WithRelationships.Result>
{
    public class Result
    {
        public string UserId { get; set; }
        public string[] Claims { get; set; }
        public int MentorCount { get; set; }
        public int MenteeCount { get; set; }
    }

    public Users_WithRelationships()
    {
        AddMap<User>(users => users.Select(user => new
        {
                UserId = user.Id,
                user.Claims,
                MentorCount = 0,
                MenteeCount = 0
        }));

        AddMap<Relationship>(relationships => relationships.Select(relationship => new
        {
                UserId = relationship.MentorId,
                Claims = (string[]) null,
                MentorCount = 0,
                MenteeCount = 1
        }));

        AddMap<Relationship>(relationships => relationships.Select(relationship => new
        {
                UserId = relationship.MenteeId,
                Claims = (string[]) null,
                MentorCount = 1,
                MenteeCount = 0
        }));

        Reduce = results => results.GroupBy(result => result.UserId).Select(g => new
        {
                UserId = g.Key,
                Claims = g.Select(x => x.Claims).FirstOrDefault(x => x != null),
                MentorCount = g.Sum(x => x.MentorCount),
                MenteeCount = g.Sum(x => x.MenteeCount)
        });
    }
}