1

次の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)
        });
    }
}
4

1 に答える 1

2

ユーザーとの関係データが既に保持されているモデルを使用した方がよい場合があります。これは次のようになります。

public class User
{
  public string Id { get; set; }
  public string Name { get; set; }
  public string[] MentorUserIds { get; set; }
  public string[] MenteeUserIds { get; set; }
}

ただし、説明したモデルに固執する場合の解決策は、複数の個別のインデックスを取り除き、必要なデータを持つ単一のマルチマップ インデックスを作成することです。

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

  public Users_WithRelationships()
  {
    AddMap<User>(users => from user in users
                          select new
                          {
                            UserId = user.Id,
                            Name = user.Name,
                            MentorCount = 0,
                            MenteeCount = 0
                          });

    AddMap<Relationship>(relationships => from relationship in relationships
                                          select new
                                          {
                                            UserId = relationship.MentorId,
                                            Name = (string)null,
                                            MentorCount = 1,
                                            MenteeCount = 0
                                          });

    AddMap<Relationship>(relationships => from relationship in relationships
                                          select new
                                          {
                                            UserId = relationship.MenteeId,
                                            Name = (string)null,
                                            MentorCount = 0,
                                            MenteeCount = 1
                                          });

    Reduce = results => 
                from result in results
                group result by result.UserId
                into g
                select new
                {
                  UserId = g.Key,
                  Name = g.Select(x => x.Name).FirstOrDefault(x => x != null),
                  MentorCount = g.Sum(x => x.MentorCount),
                  MenteeCount = g.Sum(x => x.MenteeCount)
                };
  }
}

GetReportChunkその後、カスタム DTO を投影したい場合は、1 つのインデックスに対してクエリを実行するようにメソッドを更新できます。

return db.Query<Users_WithRelationships.Result, Users_WithRelationships>()
                 .OrderBy(x => x.UserId)
                 .Skip(skip)
                 .Take(take)
                 .Select(x =>
                         new UserReportDTO
                         {
                             Name = x.Name,
                             MentorCount = x.MentorCount,
                             MenteeCount = x.MenteeCount,
                         })
                 .ToList();
于 2012-11-23T18:29:29.130 に答える