2012-05-02 34 views
6

tôi có 2 loại khác nhau đối tượng được lưu trữ trong RavenDb, đó là một mối quan hệ cha/loại trẻ em, như thế này trong JSON:Bản giảm trong RavenDb hơn 2 bộ sưu tập với bộ sưu tập con

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

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

Items/2 
{ 
    "Account": "Account/1", 
    "Value" : "50", 
    "Tags": [ 
     "tag2"] 
} 

Lưu ý rằng tôi không muốn lưu trữ chúng trong cùng một tài liệu, vì tài khoản có thể có hàng nghìn mục.

Tôi cố gắng để viết một bản đồ/giảm chỉ số đó sẽ trả lại cho tôi một cái gì đó như:

{ 
    "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" 
     }] 
} 

tức là một danh sách của tất cả các tên thẻ riêng biệt cùng với số lượng của mỗi và giá trị của họ. Tôi nghĩ rằng tôi cần phải sử dụng một bản đồ đa để ánh xạ các bộ sưu tập Tài khoản và Mục với nhau, nhưng tôi không thể tìm ra phần giảm để tạo ra phần "TagInfo" của kết quả.

Điều này có thể xảy ra không, hoặc tôi có mô hình hóa tất cả điều này sai trong Raven không?

EDIT:

Lớp tôi muốn lấy từ truy vấn này sẽ giống như thế này:

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;} 
} 

Trả lời

2

OK, vì vậy tôi đã tìm ra một cách để làm điều này một cách chấp nhận được rằng xây dựng dựa trên câu trả lời của Daniel, vì vậy tôi sẽ ghi lại nó ở đây cho bất kỳ khách du lịch nào trong tương lai (có lẽ là bản thân mình!).

tôi đã thay đổi từ cố gắng để trở lại một kết quả cho mỗi tài khoản, để một kết quả cho mỗi tài khoản/thẻ kết hợp, vì vậy chỉ số đã phải thay đổi như sau (chú ý group by trong reduce là trên 2 tài sản):

public class TagsWithCountAndValues : AbstractIndexCreationTask<Item, TagsWithCountAndValues.ReduceResult> 
{ 
    public class ReduceResult 
    { 
     public string AccountId { get; set; } 
     public string AccountName { get; set; } 
     public string TagName { get; set; } 
     public int TagCount { get; set; } 
     public int TagValue { get; set; } 
    } 

    public TagsWithCountAndValues() 
    { 
     Map = items => from item in items 
         from tag in item.Tags 
         select new ReduceResult 
         { 
          AccountId = item.AccountId, 
          TagName = tag, 
          TagCount = 1, 
          TagValue = item.Value 
         }; 

     Reduce = results => from result in results 
          where result.TagName != null 
          group result by new {result.AccountId, result.TagName} 
          into g 
          select new ReduceResult 
             { 
              AccountId = g.Key.AccountId, 
              TagName = g.Key.TagName, 
              TagCount = g.Sum(x => x.TagCount), 
              TagValue = g.Sum(x => x.TagValue), 
             }; 

     TransformResults = (database, results) => from result in results 
                let account = database.Load<Account>(result.AccountId) 
                select new ReduceResult 
                  { 
                   AccountId = result.AccountId, 
                   AccountName = account.Name, 
                   TagName = result.TagName, 
                   TagCount = result.TagCount, 
                   TagValue = result.TagValue, 
                  }; 
    } 
} 

Như trước đây, truy vấn này chỉ là:

var results = session 
    .Query<TagsWithCountAndValues.ReduceResult, TagsWithCountAndValues>() 
    .ToList(); 

kết quả của việc này sau đó có thể được chuyển đổi thành các đối tượng ban đầu tôi muốn bởi một truy vấn LINQ trong bộ nhớ. Tại thời điểm này số lượng kết quả có thể được trả về sẽ tương đối nhỏ, do đó, việc thực hiện điều này ở cuối ứng dụng có thể dễ dàng chấp nhận được. Tuyên bố LINQ là:

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 }) 
         }; 

nào cho chúng ta một đối tượng cho mỗi tài khoản, với một danh sách con của TagInfo đối tượng - một cho mỗi thẻ duy nhất.

6

Bạn không thể sử dụng nhiều đồ/Giảm chỉ số cho rằng vì bạn muốn một bản đồ trên các thẻ và một bản đồ khác trên tài khoản. Họ không có tài sản chung, vì vậy bạn không thể có nhiều bản đồ/giảm ở đây.

Tuy nhiên, bạn có thể sử dụng TransformResult thay thế. Dưới đây là làm thế nào để làm điều đó:

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 
                }; 
    } 
} 

Sau đó, bạn có thể truy vấn như thế này:

var results = session.Query<TagsWithCountAndValues.ReduceResult, TagsWithCountAndValues>() 
    .Where(x => x.AccountId == "accounts/1")       
    .ToList(); 
+0

Cảm ơn Daniel, tôi không biết về 'TransformResults'! Đó không phải là những gì tôi muốn mặc dù, tôi đã sau một kết quả cho mỗi tài khoản, với một tài sản có chứa các chi tiết thẻ, xem chỉnh sửa của tôi.Ngoài ra, TotalSum ở trên không hoạt động, vì nó tính tổng TẤT CẢ các giá trị mục, không chỉ là giá trị cho tài khoản mà tôi đang truy vấn (Tôi nghĩ rằng giảm nhu cầu nhóm trên tài khoản thay vì thẻ?) – Simon

+0

Bạn không thể có chỉ mục có một lớp lồng nhau trong kết quả của nó. Tôi không nghĩ rằng bạn có thể có được những gì bạn muốn trong một chỉ mục duy nhất. Thay vào đó, tôi thà có một vài chỉ mục độc lập và truy vấn tất cả các thông tin bạn cần hoặc thay đổi mô hình dữ liệu sao cho nó phù hợp với mô hình truy cập dữ liệu tốt hơn. –

+0

Ok, cảm ơn Daniel. Tôi nghĩ rằng đó có thể là trường hợp, nhưng không quá chắc chắn. Cảm ơn vì bạn đã dành thời gian. – Simon

Các vấn đề liên quan