0
votes

I am building an index, but the results is not as expected.

My intention is find how much clients and suppliers I have based in SomeEnumFlag in MyClass. MyClass has Name and SomeEnumFlag, its a kind of buy or sell document. So I can have documents like:

{ Name: "Some company name", SomeEnumFlag: "Buy" },
{ Name: "Another company name", SomeEnumFlag: "Buy" },
{ Name: "Another company name", SomeEnumFlag: "Sell" },
{ Name: "Another company name", SomeEnumFlag: "Sell" }

The expected result is:

  • Clients: 2; 'cause there are two distinct companies with "Buy";
  • Suppliers: 1; 'cause there is one distinct company with "Sell"

So, a company can be a client or/and a supplier based on SomeEnumFlag, and I should count each one time.

Consider the index:

public class MyClass_TotalClientsSuppliers_Index : AbstractIndexCreationTask<MyClass, MyClass_TotalClientsSuppliers_Index.Result>
{
    public class Result
    {
        public string Kind { get; set; }
        public int Total { get; set; }
    }

    public MyClass_TotalClientsSuppliers_Index()
    {
        Map = myClass => from grouped in myClass.GroupBy(c => new { Name = c.Name, Flag = c.SomeEnumFlag.ToString() })
                              select new
                              {
                                  Kind = grouped.Key.Flag,
                                  Total = 1
                              };

        Reduce = results => from result in results
                            group result by result.Kind into g
                            select new
                            {
                                Kind = g.Key,
                                Total = g.Sum(c => c.Total)
                            };
    }
}

And querying:

var resultTotalClientSupplier = session
                        .Query<MyClass_TotalClientsSuppliers_Index.Result, MyClass_TotalClientsSuppliers_Index>()
                        .ToList();

var totalClients = resultTotalClientSupplier.FirstOrDefault(c => c.Kind == eSomeEnumFlag.Buy.ToString())?.Total ?? 0;
var totalSuppliers = resultTotalClientSupplier.FirstOrDefault(c => c.Kind == eSomeEnumFlag.Sell.ToString())?.Total ?? 0;

totalClients = 2.

totalSuppliers = 2, its wrong.

But, if I write a code like this:

var myClasses = session.Query<MyClass>().ToList();

var map = from grouped in myClasses.GroupBy(c => new { Name = c.Name, Flag = c.SomeEnumFlag.ToString() })
                              select new
                              {
                                  Kind = grouped.Key.Flag,
                                  Total = 1
                              };

var reduce = from result in map
                    group result by result.Kind into g
                    select new
                    {
                        Kind = g.Key,
                        Total = g.Sum(c => c.Total)
                    };

var totalClients = reduce.FirstOrDefault(c => c.Kind == eSomeEnumFlag.Buy.ToString())?.Total ?? 0;
var totalSuppliers = reduce.FirstOrDefault(c => c.Kind == eSomeEnumFlag.Sell.ToString())?.Total ?? 0;

totalClients = 2.

totalSuppliers = 1, its right!

I did map/reduce code manually, exactly the same way, in memory, and its works as expected.

What is wrong about my Index? What am I missing? There is some limitation using group by in indexes?

Thanks in advance.

I should mention that in Map method I did a grouping with a compound key. So Name and SomeEnumFlag should work like a distinct between this two properties, with 3 total enumeration ({Some company name, Buy}, {Another company name, Buy}, {Another company name, Sell}). How many Buy? 2. How many Sell? 1. Raven Index is not working. In memory sample, that simulates behavior of map/reduce, works fine.

1
Ok - quick thing I've noticed: in your first code sample, you're querying results for results. However, in your second example, where you say things are going correctly, you're querying the previous variable "map". Was that a simple typo? - prestonsmith
Yes, that's correct, according to this raven documentation ravendb.net/docs/article-page/3.5/csharp/indexes/…. Map produce results, then I can query results in Reduce method. And the second notice, map is a variable that simulates Map method, so map has a grouping query. The only difference between my index and raven documentation is the grouping in Map funcion. - RenanStr

1 Answers

0
votes

I don't think there's anything wrong with your index, I think there's an issue with your LINQ query.

Assuming there are only 3 items, maybe try this query instead?

var totalSuppliers = reduce.Count(c => c.Kind == eSomeEnumFlag.Buy.ToString())

This shortens and makes the logic more clear I think and should get you what you're looking for? If not let me know and I'll probe a little deeper.