Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RavenDB MultiMap Index

Tags:

ravendb

I am new to RavenDB. I am trying to use a multi map index feature, though I am not sure if it is the best approach to my problem. So I have three documents: Unit, Car, People.

Car document looks like this:

{
 Id: "cars/123",
 PersonId: "people/1235",
 UnitId: "units/4321",
 Make: "Toyota",
 Model: "Prius"
}

People document looks like this:

{
   Id: "people/1235",
   FirstName: "test",
   LastName: "test"
}

And unit doc:

{
   Id: "units/4321",
   Address: "blah blah"
}

This is an abbreviated example, in my real app there are way more fields, so data de-normalization would be my last resort.

I need to create and index that will have all of this three docuemnts joined in one document. Something like this:

{
   CarId: "cars/123",
   PersonId: "people/1235",
   UnitId: "units/4321",
   Make: "Toyota",
   Model: "Prius"
   FirstName: "test",
   LastName: "test"
   Address: "blah blah"
}

// same unit different person owns a different car

{
   CarId: "cars/122",
   PersonId: "people/1236",
   UnitId: "units/4321",
   Make: "Toyota",
   Model: "4runner"
   FirstName: "test",
   LastName: "test"
   Address: "blah blah"
}

In a relational database I would just use two joins to People and Unit tables by ids and my car table would be an aggregate entity.

Here is the index definition that I have:

 public class MyMultiIndex : AbstractMultiMapIndexCreationTask<JoinedDocument>
 {
    public MyMultiIndex()
    {
        // creating maps
        AddMap<Car>(cars => cars.Select(e => new { e.CarId, e.Make, e.Model, PersonId = e.PersonId, UnitId = e.UnitId, FirstName = (null)string, LastName = (null)string, Address = (nul)string }));
        AddMap<People>(people => people.Select(e => new { CarId = (string)null, Make = (string)null, Model = (string)null, PersonId = e.Id, UnitId = (null)string, FirstName = e.FirstName, LastName = e.LastName, Address = (nul)string }));
        AddMap<Unit>(people => people.Select(e => new { CarId = (string)null, Make = (string)null, Model = (string)null, PersonId = (null)string, UnitId = e.null, FirstName = (nul)string , LastName = (nul)string , Address = e.Address }));

        Reduce = results => from result in results
                            group result by result.CarId
                            into g
                            select new JoinedDocument
                            {
                                CarId = g.Key,
                                PersonId = g.First(e => e.CarId == g.Key).PersonId,
                                UnitId = g.First(e => e.CarId == g.Key).UnitId,
                                Model = g.First(e => e.CarId == g.Key).Model,
                                Make = g.First(e => e.CarId == g.Key).Make,

                                **// this never works. It is like result set does not contain anything with this personId. It looks like AddMap for people document did not work.**

                                FirstName = results.First(e => e.PersonId == g.First(ie => ie.CarId == g.Key).PersonId).FirstName,

                                **// this never works. It is like result set does not contain anything with this personId. It looks like AddMap for people document did not work.**

                                LastName = results.First(e => e.PersonId == g.First(ie => ie.CarId == g.Key).PersonId).LastName,

                                **// this never works. It is like result set does not contain anything with this personId. It looks like AddMap for unit document did not work.**

                                UnitAddress = results.First(e => e.UnitId == g.First(ie => ie.CarId == g.Key).UnitId).LastName,
                           };
        Index(map => map.Model, FieldIndexing.Analyzed);
        Index(map => map.Make, FieldIndexing.Analyzed);
        Index(map => map.LastName, FieldIndexing.Analyzed);
        Index(map => map.FirstName, FieldIndexing.Analyzed);
        Index(map => map.Make, FieldIndexing.Analyzed);
        Index(map => map.UnitAddress, FieldIndexing.Analyzed);
    }
 }

When RavenDb runs this index I see errors when it is trying to run the Reduce function I have provided. It throws error when I am trying to match a record where person's first name and last name exist, same happens with the unit.

like image 223
milagvoniduak Avatar asked Nov 05 '22 01:11

milagvoniduak


2 Answers

It looks like you're trying to fit a document database with an object model that has relationships. This blog may help you:

Keeping a Domain Model Pure with RavenDB

Keep in mind that this isn't the recommended use of RavenDB, but sometimes it's necessary, and this is a good way to handle it.

like image 59
Bob Horn Avatar answered Dec 21 '22 16:12

Bob Horn


Can you have a car with no owner? or an address with no resident? If its false in both cases, I would model the car and unit to be embedded inside a person. So the person becomes your aggregate root and to get to a car or a unit you must go through a person.

like image 41
afif Avatar answered Dec 21 '22 16:12

afif