【问题标题】:RavenDB Map/Reduce/Transform on nested, variable-length arraysRavenDB Map/Reduce/Transform 在嵌套的可变长度数组上
【发布时间】:2013-07-08 23:33:12
【问题描述】:

我是 RavenDB 的新手,到目前为止我很喜欢它。我还有一个要为我的项目创建的索引。

问题

我有成千上万的调查回复(即“Submissions”),每个提交都有一系列特定问题的答案(即“Answers”),每个答案都有一系列选择的选项(即“Values”)。

这是单个Submission 的基本外观:

{
  "SurveyId": 1,
  "LocationId": 1,
  "Answers": [
    {
      "QuestionId": 1,
      "Values": [2,8,32],
      "Comment": null
    },
    {
      "QuestionId": 2,
      "Values": [4],
      "Comment": "Lorem ipsum"
    },
    ...more answers...
  ]
}

更多问题:我必须能够按 SurveyId、LocationId、QuestionId、创建日期进行过滤。据我了解,这是在查询时完成的......我只需要确保这些属性存在于转换结果中(或者是减少结果?或两者兼而有之?)。如果我是对的,那么这不是问题。

要求的结果

每个调查的每个问题都需要一个对象,该对象给出每个选项的总和。希望它是不言自明的:

[
    {
        SurveyId: 1,
        QuestionId: 1,
        NumResponses: 976,
        NumComments: 273,
        Values: {
            "1": 452, // option 1 selected 452 times
            "2": 392, // option 2 selected 392 times
            "4": 785  // option 4 selected 785 times
        }
    },
    {
        SurveyId: 1,
        QuestionId: 2,
        NumResponses: 921,
        NumComments: 46,
        Values: {
            "1": 325,
            "2": 843,
            "4": 119,
            "8": 346,
            "32": 524
        }
    },
    ...
]

我的尝试

我没有走多远,我认为this post 正在引导我走上正确的道路,但它对我的价值观列表没有帮助。我已经搜索和搜索,但找不到任何方向来处理这样的嵌套数组。到目前为止,这是我所拥有的:

地图:

from submission in docs.Submissions
from answer in submission.Answers
where answer.WasSkipped != true && answer.Value != null
select new {
    SubmissionDate = submission["@metadata"]["Last-Modified"],
    SurveyId = submission.SurveyId,
    LocationId = submission.LocationId,
    QuestionId = answer.QuestionId,
    Value = answer.Value
}

减少:

??

变换:

from result in results
from answer in result.Answers
where answer.WasSkipped != true && answer.Value != null
select new {
    SubmissionDate = result["@metadata"]["Last-Modified"],
    SurveyId = result.SurveyId,
    LocationId = result.LocationId,
    QuestionId = answer.QuestionId,
    Value = answer.Value
}

不管怎样,它都托管在 RavenHQ 上。

我一直在研究这个问题已经很长时间了,但无法做到这一点。非常感谢任何帮助我获得所需结果的帮助!

【问题讨论】:

    标签: mapreduce ravendb ravenhq


    【解决方案1】:

    假设您的 C# 类如下所示:

    public class Submission
    {
        public int SurveyId { get; set; }
        public int LocationId { get; set; }
        public IList<Answer> Answers { get; set; }
    }
    
    public class Answer
    {
        public int QuestionId { get; set; }
        public int[] Values { get; set; }
        public string Comment { get; set; }
    }
    

    如果您运行的是 RavenDB 2.5.2637 或更高版本,您现在可以使用字典结果类型:

    public class Result
    {
        public int SurveyId { get; set; }
        public int QuestionId { get; set; }
        public int NumResponses { get; set; }
        public int NumComments { get; set; }
        public Dictionary<int, int> Values { get; set; }
    }
    

    如果您运行的是早期版本(包括 2.0 版本),那么您将无法使用字典,但您可以改用 IList&lt;KeyValuePair&lt;int,int&gt;&gt;

    这是索引:

    public class TestIndex : AbstractIndexCreationTask<Submission, Result>
    {
        public TestIndex()
        {
            Map = submissions =>
                  from submission in submissions
                  from answer in submission.Answers
                  select new
                  {
                      submission.SurveyId,
                      answer.QuestionId,
                      NumResponses = 1,
                      NumComments = answer.Comment == null ? 0 : 1,
                      Values = answer.Values.ToDictionary(x => x, x => 1)
                      //Values = answer.Values.Select(x => new KeyValuePair<int, int>(x, 1))
                  };
    
            Reduce = results =>
                     from result in results
                     group result by new { result.SurveyId, result.QuestionId }
                     into g
                     select new
                     {
                         g.Key.SurveyId,
                         g.Key.QuestionId,
                         NumResponses = g.Sum(x => x.NumResponses),
                         NumComments = g.Sum(x => x.NumComments),
                         Values = g.SelectMany(x => x.Values)
                                   .GroupBy(x => x.Key)
                                   .ToDictionary(x => x.Key, x => x.Sum(y => y.Value))
                                   //.Select(x => new KeyValuePair<int, int>(x.Key, x.Sum(y => y.Value)))
                     };
        }
    }
    

    (无需转换步骤。)

    如果您不能使用 2.5.2637 或更高版本,请将 .ToDictionary 行替换为它们正下方的注释行,并在结果类中使用 IList&lt;KeyValuePair&lt;int,int&gt;&gt;

    允许在 map/reduce 中使用字典的修复基于您的帖子帮助识别的 this issue。谢谢!

    【讨论】:

    • ...感谢提示在 v2.0 上使用 IList>
    • 这很好用,但也需要按转换结果类中不存在的字段进行过滤(例如,我只想要特定时间段内提交的数据)。这是一个足够大的问题,我应该作为一个单独的问题提出吗?
    • 嗯,我没有看到任何这些对象上的任何日期,而且这里的解决方案没有转换,所以您可能应该打开一个新问题,仅包含该问题的细节。
    • 好的,在这里完成:stackoverflow.com/questions/17686654/…
    猜你喜欢
    • 1970-01-01
    • 2012-08-07
    • 1970-01-01
    • 1970-01-01
    • 2016-10-05
    • 1970-01-01
    • 2021-07-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多