Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RavenDB Transformer Include List of documents

Tags:

ravendb

I am kind of stuck on using the include with a RavenDB Transformer. Say I have the following document classes:

public class Processor
{
    public string Id { get; set; }
    // other properties
}

public class Job
{
    public string Id { get; set; }
    public string ProcessorId { get; set; }
    // other properties
}

Hers is my view model:

public class ProcessorStatsViewModel
{
    public string Id { get; set; }
    public int JobCount { get; set; }
    // other properties
}

In my tranformer I would like to query the Processors Document Store and do an include on the Jobs Store looking for every job with a matching Processor ID. All of the search results I found describe how to do this when the Processor class has the list of JobId's. Is there a way to do this in RavenDB?

The transformer I would like could look something like:

public Processors_StatsViewModel()
{
    TransformerResults = procs => 
        from p in procs
        let jobs = Include<Jobs>(p.Id) // how can i specify something like where p.Id == j.ProcessorId ?
        select new
        {
            p.Id
            JobCount = jobs.Count
            // other stuff
        }
}

All of the Transformer LoadDocument, Include, and Recurse methods expect the class being queried to have a list reference ID's but in my case in need the opposite.

Is this something I can even do in RavenDB or am I missing something?

like image 482
Steven Garcia Avatar asked Nov 10 '22 11:11

Steven Garcia


1 Answers

You can not do what you want to do with only a transformer and your current domain model. If the processors did indeed know about its jobs you could do this with a transformer kind of like the one you have.

However, you can achieve something similar with a Map/Reduce index and then a Transformer over the result of the Map/Reduce index. It all depends on what "other stuff" you want to present, but this is a way to get all Processes and its job count and then adding more information with a transformer:

Map/Reduce index to get job count by processor:

public class Jobs_ByProcessor : AbstractIndexCreationTask<Job, Jobs_ByProcessor.ReduceResult>
{
    public class ReduceResult
    {
        public string ProcessorId { get; set; }
        public int JobCount { get; set; }
    }

    public Jobs_ByProcessor()
    {
        Map = jobs => from job in jobs
                      select new ReduceResult
                      {
                          ProcessorId = job.ProcessorId,
                          JobCount = 1
                      };

        Reduce = results => from result in results
                            group result by result.ProcessorId
                                into g
                                select new
                                {
                                    ProcessorId = g.Key,
                                    JobCount = g.Sum(x => x.JobCount)
                                };
    }
}

Transformer:

public class ProcessorJobTransformer : AbstractTransformerCreationTask<Jobs_ByProcessor.ReduceResult>
{
    public ProcessorJobTransformer()
    {
        TransformResults = results => from result in results
            let processor = LoadDocument<Processor>(result.ProcessorId)
            select new
            {
                Id = result.ProcessorId,
                Name = processor.Name,
                JobCount = result.JobCount
            };
    }
}

This would give you a result like this: enter image description here Id and JobCount comes from the Reduce result of the index and the Name comes from the Transformer (via LoadDocument).

However, if you need this results but more information from the Job document, you might have to go a different route entirely.

Hope this helps!

like image 57
Jens Pettersson Avatar answered Dec 21 '22 15:12

Jens Pettersson