如何在Ravendb中反向索引相关文档

时间:2016-11-16 14:48:00

标签: c# ravendb document-database

Indexing Related Documents的示例II中,按名称和书名在作者上建立索引。相关实体看起来像这样:

public class Book {
   public string Id { get; set; }
   public string Name { get; set; }
}

public class Author {
    public string Id { get; set; }
    public string Name { get; set; }
    public IList<string> BookIds { get; set; }
}

即。只有Author包含有关该关系的信息。该信息用于构建所述索引。

但是我如何构建一个关于Books by Authors的索引(假设一本书可能有多个作者)?

修改

这本书/作者的比喻只是到目前为止。我将举一个更接近我实际用例的例子:

假设我们有一些与地点相关的任务:

public class Location {
    public string Id { get; set; }
    public double Latitude { get; set; }
    public double Longitude { get; set; }
}

public class Task {
   public string Id { get; set; }
   public string Name { get; set; }
   public string LocationId { get; set; }
   public Status TaskStatus { get; set; }
}

我有一个端点将Locations作为GeoJson提供给客户端中的地图视图。我想根据与其关联的任务的状态为地点着色。地图通常会显示500-2000个位置。

对位置的查询实现为流式查询。

使用Ayende最初答案中指出的查询方法,我可能会这样做:

foreach (var location in locationsInView)
{
    var completedTaskIds = await RavenSession.Query<Task>()
        .Where(t => t.LocationId == location.Id && t.TaskStatus == Status.Completed)
        .ToListAsync();

    //
    // Construct geoJson from location and completedTaskIds
    //
}

这会导致针对RavenDB执行500-2000个查询,这似乎不对。 这就是为什么我最初认为我需要一个索引来构建我的结果。

我已经读过RavenDB默认缓存所有内容,因此这可能不是问题。另一方面,实施这种方法后,我收到一个错误(“......此会话允许的最大请求数(30)......”)。

解决这个问题的好方法是什么?

2 个答案:

答案 0 :(得分:1)

您不能以这种方式索引它们。 但你也不需要。

如果您想查找作者的所有图书,请加载作者并获得完整列表。

答案 1 :(得分:0)

您可以使用multi map/reduce index执行此操作。

关于感兴趣对象的所有真实来源都映射到一个共同的对象类型(Result)。然后,通过Id减少分组并仅保留相关部分,创建关于每个对象的真实的“合并”(在这种情况下为Book)。因此,使用书籍/作者示例,其中几位作者可能对同一本书做出了贡献,您可以执行以下操作。

请注意,map和reduce步骤必须输出相同类型的对象,这就是author.Id在作者映射过程中被包装在列表中的原因。

为简洁起见,

Author.Name被排除在外,但可以与Author.Id完全相同的方式包含在内。

public class BooksWithAuthors : AbstractMultiMapIndexCreationTask<BooksWithAuthors.Result>
{
    public class Result 
    {
        string Id;
        string Title;
        IEnumerable<string> AuthorIds;
    }

    public BooksWithAuthors()
    {
        AddMap<Book>(book => from book in books
                             select new
                             {
                                 Id = book.Id,
                                 Title = book.Title,
                                 AuthorIds = null;
                             });

        AddMap<Author>(author => from author in authors
                                 from bookId in author.bookIds
                                 select new
                                 {
                                     Id = bookId,
                                     Title = null,
                                     AuthorIds = new List<string>(){ author.Id };
                                 });

        Reduce = results => from result in results
                            group result by result.Id
                            into g
                            select new
                            {
                                Id = g.Key,
                                Title = g.Select(r => r.Title).Where(t => t != null).First(),
                                AuthorIds = g.Where(r => r.AuthorIds != null).SelectMany(r => r.AuthorIds)
                            };
    }
}