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

How to index related documents in reverse direction in Ravendb

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 包含有关关系的信息。此信息用于构建所述索引。

但是我如何按作者构建书籍索引(假设一本书可能有多个作者)?

编辑:

book/author 类比到此为止。我将举一个更接近我的实际用例的例子:

假设我们有一些与位置相关的任务:

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)...”)。

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

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

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

您可以使用 multi map/reduce index 来完成此操作。

有关感兴趣对象的所有真实来源都映射到一个通用对象类型 (Result)。然后,此映射按 Id 减少分组并仅保留相关部分,从而创建关于每个对象的 "merge" 个真相(在本例中为 Book)。因此,使用 Book/Author 示例,其中多个作者可能对同一本书做出了贡献,您可以执行如下操作。

请注意,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)
                            };
    }
}