How to index related documents in reverse direction in Ravendb

狂风中的少年 提交于 2019-12-23 01:36:12

问题


In Example II of Indexing Related Documents, an index is built over Authors by Name and Book title. The relevant entities look like so:

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

I.e. only the Author holds information about the relation. This information is used in constructing said index.

But how would I construct an index over Books by Authors (assuming a book could have multiple authors)?

Edit:

The book/author analogy only goes so far. I'll make an example that's closer to my actual use case:

Suppose we have some tasks that are tied to locations:

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

I have an endpoint serving Locations as GeoJson to a map view in a client. I want to color the Locations depending on status of Tasks associated with them. The map would typically show 500-2000 locations.

The query on locations is implemented as a streaming query.

Using the query-method indicated in Ayende's initial answer, I might do something like:

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

This results in 500-2000 queries being executed against RavenDB, which doesn't seem right. This is why I initially thought I needed an index to construct my result.

I have since read that RavenDB caches everything by default, so that might be a non-issue. On the other hand, having implemented this approach, I get an error ("...maximum number of requests (30) allowed for this session...").

What is a good way of fixing this?


回答1:


You cannot index them in this manner. But you also don't need to.

If you want to find all the books by an author, you load the author and you have the full list.




回答2:


You can do this using a multi map/reduce index.

All sources of truth about the objects of interest are mapped to a common object type (Result). This mapping is then reduced grouping by Id and keeping just the relevant pieces, creating a "merge" of truths about each object (Book in this case). So using the Book/Author example, where several Authors might have contributed to the same book, you could do something like the following.

Note that the map and reduce steps must output the same type of object, which is why author.Id is wrapped in a list during the mapping from author.

Author.Names are excluded for brevity, but could be included in the exact same way as 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)
                            };
    }
}


来源:https://stackoverflow.com/questions/40635083/how-to-index-related-documents-in-reverse-direction-in-ravendb

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!