【问题标题】:How to index related documents in reverse direction in Ravendb如何在 Ravendb 中反向索引相关文档
【发布时间】:2017-03-30 19:48:51
【问题描述】:

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

我有一个端点将位置作为 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)...”)。

有什么好的方法可以解决这个问题?

【问题讨论】:

  • 你可以这样吗? .Where(t =&gt; locationsInView.Any(x=&gt; x.Id == t.LocationId) &amp;&amp;.... 而不是 foreach?
  • 我试过了。但不是。我认为是因为 Raven 不能在内部执行任意 C#,所以 locationsInView.Any(...) 不起作用。

标签: c# ravendb document-database


【解决方案1】:

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

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

【讨论】:

  • 感谢您的回答,Ayende!我可能不够具体。我已经更新了问题。
  • 我现在使用多映射/归约索引实现了类似于LocationsWithTaskIds 的索引。它似乎工作正常,但既然你说这是不可能的,我想知道你是否认为这是不好的做法。你能详细说明一下吗?
【解决方案2】:

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

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

请注意,map 和 reduce 步骤必须输出相同类型的对象,这就是为什么 author.Id 在从 author 映射期间被包装在一个列表中的原因。

为简洁起见,将Author.Names 排除在外,但可以以与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)
                            };
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多