You can achieve this using the MultiMap / Reduce index, but you will need hacking:
1) You will need to reduce the use of strings, not directions. You can still return values ββas pointers in your AB class, as I will demonstrate below.
2) You cannot name the first property of your AB class "Id", since the raven will try to translate it to "__document_id". So call it βAIdβ and it will work fine.
3) In the display phase, you need to manipulate the lines yourself to interrupt the document key prefix.
Here is an example program that brings it all together. This demonstrates that it really works, but I think it also shows why Ayende prefers string identifiers, so you don't have to deal with this mess.
using System; using System.Linq; using Raven.Client.Document; using Raven.Client.Indexes; namespace RavenScratchTest { class Program { static void Main() { var documentStore = new DocumentStore { Url = "http://localhost:8080" }; documentStore.Initialize(); IndexCreation.CreateIndexes(typeof(Program).Assembly, documentStore); using (var session = documentStore.OpenSession()) { var b = new B { Id = Guid.NewGuid(), Name = "Foo" }; var a = new A { Id = Guid.NewGuid(), BId = b.Id }; session.Store(a); session.Store(b); session.SaveChanges(); } using (var session = documentStore.OpenSession()) { var a = session.Query<A>().Customize(x => x.WaitForNonStaleResults()).First(); var b = session.Query<B>().Customize(x => x.WaitForNonStaleResults()).First(); Console.WriteLine("A: Id = {0}", a.Id); Console.WriteLine(" BId = {0}", a.BId); Console.WriteLine(); Console.WriteLine("B: Id = {0}", b.Id); Console.WriteLine(" Name = {0}", b.Name); Console.WriteLine(); var guid = a.Id; var ab = session.Query<AB, MyIndex>().Customize(x => x.WaitForNonStaleResults()) .FirstOrDefault(t => t.AId == guid); if (ab == null) Console.WriteLine("AB: NULL"); else { Console.WriteLine("AB: AId = {0}", ab.AId); Console.WriteLine(" BId = {0}", ab.BId); Console.WriteLine(" BName = {0}", ab.BName); Console.WriteLine(); } } Console.WriteLine(); Console.WriteLine("Done."); Console.ReadLine(); } } class A { public Guid Id { get; set; } public Guid BId { get; set; } } class B { public Guid Id { get; set; } public string Name { get; set; } } class AB { public Guid AId { get; set; } public Guid BId { get; set; } public string BName { get; set; } } class MyIndex : AbstractMultiMapIndexCreationTask<MyIndex.ReduceResult> { public MyIndex() { AddMap<A>(docs => from a in docs select new { AId = a.Id.ToString().Split('/')[1], a.BId, BName = (string)null }); AddMap<B>(docs => from b in docs select new { AId = (string)null, BId = b.Id.ToString().Split('/')[1], BName = b.Name }); Reduce = results => from result in results group result by result.BId into g select new { g.FirstOrDefault(x => x.AId != null).AId, BId = g.Key, g.FirstOrDefault(x => x.BName != null).BName }; } internal class ReduceResult { public string AId { get; set; } public string BId { get; set; } public string BName { get; set; } } } }
source share