C# 用于嵌套查询的RavenDB索引

C# 用于嵌套查询的RavenDB索引,c#,linq,indexing,ravendb,C#,Linq,Indexing,Ravendb,我是RavenDB的新手,正在努力找到以下问题的解决方案: 我有一个名为ServiceCalls的集合,看起来像这样: public class ServiceCall { public int ID { get; set; } public string IncidentNumber { get; set; } public string Category { get; set; } public string SubCa

我是RavenDB的新手,正在努力找到以下问题的解决方案:

我有一个名为ServiceCalls的集合,看起来像这样:

public class ServiceCall
    {
        public int ID { get; set; }
        public string IncidentNumber { get; set; }
        public string Category { get; set; }
        public string SubCategory { get; set; }
        public DateTime ReportedDateTime { get; set; }
        public string Block { get; set; }
        public decimal Latitude { get; set; }
        public decimal Longitude { get; set; }
    }
        Map = docs => from doc in docs
                      select new
                      {
                          Category = doc.Category,
                          CategoryCount = 1,
                          ServiceCalls = doc,
                      };
        Reduce = results => from result in results
                            group result by result.Category into g
                            select new
                            {
                                Category = g.Key,
                                CategoryCount = g.Count(),
                                ServiceCalls = g.Select(i => i.ServiceCalls)
                            };
var q = session.Query<ServiceCallsByCategory, ServiceCalls_CallsByCategory>()
               .Include<ServiceCallsByCategory, ServiceCall>(x => x.ServiceCallIds);
我有一个名为ServiceCalls/CallsByCategory的索引,如下所示:

public class ServiceCall
    {
        public int ID { get; set; }
        public string IncidentNumber { get; set; }
        public string Category { get; set; }
        public string SubCategory { get; set; }
        public DateTime ReportedDateTime { get; set; }
        public string Block { get; set; }
        public decimal Latitude { get; set; }
        public decimal Longitude { get; set; }
    }
        Map = docs => from doc in docs
                      select new
                      {
                          Category = doc.Category,
                          CategoryCount = 1,
                          ServiceCalls = doc,
                      };
        Reduce = results => from result in results
                            group result by result.Category into g
                            select new
                            {
                                Category = g.Key,
                                CategoryCount = g.Count(),
                                ServiceCalls = g.Select(i => i.ServiceCalls)
                            };
var q = session.Query<ServiceCallsByCategory, ServiceCalls_CallsByCategory>()
               .Include<ServiceCallsByCategory, ServiceCall>(x => x.ServiceCallIds);
因此,输出为:

public class ServiceCallsByCategory
{
    public string Category { get; set; }
    public int CategoryCount { get; set; }
    public IEnumerable<ServiceCall> ServiceCalls { get; set; }
}
公共类服务调用ByCategory
{
公共字符串类别{get;set;}
public int CategoryCount{get;set;}
公共IEnumerable服务调用{get;set;}
}
使用此查询,一切正常

var q = from i in session.Query<ServiceCallsByCategory>("ServiceCalls/CallsByCategory") select i
var q=from会话中的i.Query(“ServiceCalls/CallsByCategory”)选择i
我完全不知所措的地方是编写一个索引,允许我按ReportedDateTime进行查询。我可以这样做:

    var q = from i in session.Query<ServiceCallsByCategory>("ServiceCalls/CallsByCategory")
            where i.ServiceCalls.Any(x=>x.ReportedDateTime >= new DateTime(2012,10,1)) 
            select i
var q=来自会话中的i.Query(“ServiceCalls/CallsByCategory”)
其中i.ServiceCalls.Any(x=>x.ReportedDateTime>=新日期时间(2012,10,1))
选择i

非常感谢您的指导。

您能否将ReportedDateTime添加到地图中,并在Reduce中汇总?如果您只关心每个类别的最大值,那么像这样的内容就足够了

Map = docs => from doc in docs
                      select new
                      {
                          Category = doc.Category,
                          CategoryCount = 1,
                          ServiceCalls = doc,
                          ReportedDateTime
                      };
        Reduce = results => from result in results
                            group result by result.Category into g
                            select new
                            {
                                Category = g.Key,
                                CategoryCount = g.Sum(x => x.CategoryCount),
                                ServiceCalls = g.Select(i => i.ServiceCalls)
                                ReportedDateTime = g.Max(rdt => rdt.ReportedDateTime)
                            };
然后,您可以仅根据聚合的ReportedDateTime进行查询:

var q = from i in session.Query<ServiceCallsByCategory>("ServiceCalls/CallsByCategory")
            where i.ReportedDateTime >= new DateTime(2012,10,1) 
            select i
var q=来自会话中的i.Query(“ServiceCalls/CallsByCategory”)
其中i.ReportedDateTime>=新日期时间(2012,10,1)
选择i
有几件事

  • reduce子句中不能有
    .Count()
    方法。如果你仔细观察,你会发现你的计数是错误的。从构建2151开始,这实际上会引发一个异常。相反,您需要
    CategoryCount=g.Sum(x=>x.CategoryCount)


  • 您总是希望贴图的结构与reduce的结构相匹配。如果要构建事物列表,那么应该映射每个事物的单个元素数组,并在reduce步骤中使用
    。SelectMany()
    。你现在拥有它的方式只会因为一个怪癖而起作用,这个怪癖可能会在某个时候被修复

  • 通过将结果构建为ServiceCalls列表,可以将整个文档复制到索引存储中。这不仅效率低下,而且没有必要。您最好只保留ID的列表。Raven有一个
    .Include()
    方法,如果需要检索完整文档,可以使用该方法。这里的主要优点是,即使索引结果仍然过时,您也可以保证获得每个项目的最新数据

  • 将这三者放在一起,正确的索引将是:

    public class ServiceCallsByCategory
    {
        public string Category { get; set; }
        public int CategoryCount { get; set; }
        public int[] ServiceCallIds { get; set; }
    }
    
    public class ServiceCalls_CallsByCategory : AbstractIndexCreationTask<ServiceCall, ServiceCallsByCategory>
    {
        public ServiceCalls_CallsByCategory()
        {
            Map = docs => from doc in docs
                          select new {
                                         Category = doc.Category,
                                         CategoryCount = 1,
                                         ServiceCallIds = new[] { doc.ID },
                                     };
            Reduce = results => from result in results
                                group result by result.Category
                                into g
                                select new {
                                               Category = g.Key,
                                               CategoryCount = g.Sum(x => x.CategoryCount),
                                               ServiceCallIds = g.SelectMany(i => i.ServiceCallIds)
                                           };
        }
    }
    
    公共类服务调用ByCategory
    {
    公共字符串类别{get;set;}
    public int CategoryCount{get;set;}
    public int[]ServiceCallIds{get;set;}
    }
    公共类ServiceCalls\u CallsByCategory:AbstractIndexCreationTask
    {
    公共服务呼叫(CallsByCategory)
    {
    Map=docs=>来自文档中的文档
    选择新的{
    类别=单据类别,
    类别计数=1,
    ServiceCallIds=new[]{doc.ID},
    };
    Reduce=results=>from result in results
    按结果对结果进行分组。类别
    进入g
    选择新的{
    类别=g.键,
    CategoryCount=g.Sum(x=>x.CategoryCount),
    ServiceCallIds=g.SelectMany(i=>i.ServiceCallIds)
    };
    }
    }
    
    使用includes查询它,如下所示:

    public class ServiceCall
        {
            public int ID { get; set; }
            public string IncidentNumber { get; set; }
            public string Category { get; set; }
            public string SubCategory { get; set; }
            public DateTime ReportedDateTime { get; set; }
            public string Block { get; set; }
            public decimal Latitude { get; set; }
            public decimal Longitude { get; set; }
        }
    
            Map = docs => from doc in docs
                          select new
                          {
                              Category = doc.Category,
                              CategoryCount = 1,
                              ServiceCalls = doc,
                          };
            Reduce = results => from result in results
                                group result by result.Category into g
                                select new
                                {
                                    Category = g.Key,
                                    CategoryCount = g.Count(),
                                    ServiceCalls = g.Select(i => i.ServiceCalls)
                                };
    
    var q = session.Query<ServiceCallsByCategory, ServiceCalls_CallsByCategory>()
                   .Include<ServiceCallsByCategory, ServiceCall>(x => x.ServiceCallIds);
    
    var q=session.Query()
    .包括(x=>x.ServiceCallIds);
    
    当您需要一个文档时,您仍然可以使用
    session.load(id)
    加载它,但Raven不必往返服务器获取它

    现在-这并没有解决您关于如何按日期筛选结果的问题。为此,你真的需要考虑一下你想要完成什么。以上所有内容都假设您确实希望同时显示每个类别的每个服务调用。大多数情况下,这是不实际的,因为您希望对结果进行分页。你可能甚至不想使用我上面描述的东西。我在这里做了一些宏大的假设,但大多数情况下,人们会按类别过滤,而不是按类别分组

    假设您有一个只计算类别的索引(上面的索引没有服务调用列表)。您可以使用它来显示概览屏幕。但是你不会对每个类别中的文档感兴趣,直到你点击一个并钻入详细信息屏幕。在这一点上,您知道自己属于哪个类别,并且可以根据该类别进行筛选,并将其缩减为一个没有静态索引的日期范围:

    var q = session.Query<ServiceCall>().Where(x=> x.Category == category && x.ReportedDateTime >= datetime)
    
    var q=session.Query()。其中(x=>x.Category==Category&&x.ReportedDateTime>=datetime)
    
    如果我错了,您确实需要显示所有类别中的所有文档,按类别分组,并按日期过滤,那么您将不得不采用我描述的高级技术。如果这真的是你需要的,请在评论中告诉我,我会看看是否能为你写。您需要Raven 2.0才能使其正常工作

    另外-要非常小心为ReportedDateTime存储的内容。如果你要做任何比较,你需要了解日历时间和瞬时时间之间的区别。日历时间有一些怪癖,比如夏令时转换、时区差异等等。即时时间跟踪事件发生的瞬间,不管是谁问。您可能希望使用即时时间,这意味着要么使用UTC
    DateTime
    ,要么切换到
    DateTimeOffset
    ,这样您就可以