次のUser
ようなクラスがあるとします。
public class User
{
public string Id {get; set;}
public string Name {get; set;}
}
各ユーザーは、メンター、メンティー、またはその両方になることができます。Relationship
これは次のクラスで表されます。
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 にクエリを実行してすべてのリストを取得し、これをインスタンスUsers
のリストに変換します。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();
}
MentorCount
ご覧のとおり、との値を取得する最善の方法を見つけるのに苦労していMenteeCount
ます。仕事をしているはずだと思ういくつかの Map/Reduce インデックスを作成しましたが、それらを使用して目的の結果を得る方法がわかりません。
質問
複数の集計フィールドを単一のクエリに含める最良の方法は何ですか?
編集1
@Matt Johnson:私はあなたのインデックスを実装しました(最後を参照)。現在、誰かが興味を持っている場合に備えて、次のようなレポートクエリが機能しています。
ワーキング ユーザー レポート クエリ
public List<UserDTO> GetReportChunk(IDocumentSession db, Claim claim, int skip = 0, int take = 1024)
{
var results = new List<UserDTO>();
db.Query<RavenIndexes.Users_WithRelationships.Result, RavenIndexes.Users_WithRelationships>()
.Include(o => o.UserId)
.Where(x => x.Claims.Any(c => c == claim.ToString()))
.OrderBy(x => x.UserId)
.Skip(skip)
.Take(take)
.ToList()
.ForEach(p =>
{
var user = db.Load<User>(p.UserId);
results.Add(new UserDTO
{
UserName = user.UserName,
Email = user.Email,
// Lots of other User properties
MentorCount = p.MentorCount.ToString(),
MenteeCount = p.MenteeCount.ToString()
});
});
return results;
}
マルチマップ インデックス
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)
});
}
}