More Map/Reduce confusion :( Can someone help me please?

46 views
Skip to first unread message

Justin A

unread,
May 27, 2016, 8:28:54 AM5/27/16
to RavenDB - 2nd generation document database
Hi All again.

Once more, I'm trying to do another Map/Reduce index to create a sorta summary.

I'm trying to figure out how many Students are part of a each class, in a School.

Example output.

ClassId   | Class | School     | Number of students
---------------------------------------------------
classes/1 | CS101 | RedSchool  | 12
classes/2 | CS102 | RedSchool  | 19
classes/3 | RA500 | RedSchool  | 5
classes/4 | CS101 | BlueSchool | 21

And here's the models..

public class SchoolClass
{
    public string Id;
    public string Name;
    public string School;
}

public class Student
{
    public string Id;   // students/1
    public string Name; // Jane Austin
    public string[] Classes; // classes/1, classes/2, classes/1121
}

So can anyone help me please?

At first I tried a normal Map/Reduce with a single map and a single reduce. (pseduo code below)

public class StudentClasses_GetAll : AbstractIndexCreationTask<StudentClass, StudentClasses_GetAll.Result>
{
    public StudentClasses_GetAll()
    {
        Map = studentClasses => from studentClass in studentClasses
                                select new Result
                                {
                                    Id = studentClass.Id,
                                    Name = office.Name
                                    Users = 0 // ??????
                                };

        Reduce = results => from result in results
                            group result  by result.Id
                            into g
                            select new Result
                            {
                                Id = g.Key,
                                Name = results.Single(x => x.Id == g.Key).Name,
                                Users = ????
                            }

        Sort(o => o.Name, SortOptions.String);
        Store(o => o.Id, FieldStorage.Yes);
        Store(o => o.Name, FieldStorage.Yes);
    }

    public class Result
    {
        public string Id { get; set; }
        public string Name { get; set; }
        public int Users { get; set; }
    }
}


But it just looks so wrong. Like how do i sum the users? even feels wrong, how i'm retrieving the Name of the class....

Next I thought about a multimap. But then i sorta couldn't even visualize what I'm suppose to do.

My gut feeling is like .. i'm suppose to start off with the 'Student' collection .. and somehow work my way 'up' to the offices.. somehow?

Could anyone help, please?

Tommy Höglund

unread,
May 27, 2016, 9:40:23 AM5/27/16
to RavenDB - 2nd generation document database
I guess you could try something like this. Untested code...

public class StudentClasses_GetAll : AbstractMultiMapIndexCreationTask<StudentClasses_GetAll.Result>
   
{
       
public StudentClasses_GetAll()
       
{
           
AddMap<SchoolClass>(classes => from @class in classes
               
select new
               
{
                   
Id = @class.Id,
                   
Class = @class.Name,
                   
School = @class.School,
                   
Users = 0
               
});

           
AddMap<Student>(studens => from student in studens
                                       
from @class in student.Classes
                                           
select new Result
                                           
{
                                               
Id = @class,
                                               
Class = null,
                                               
School = null,
                                               
Users = 1
                                           
});



           
Reduce = results => from result in results
               
group result by result.Id
               
into g
               
select new Result
               
{
                   
Id = g.Key,

                   
Class = g.First(x => x != null).Class,
                   
School = g.First(x => x != null).School,
                   
Users = g.Sum(x => x.Users)

               
};
       
}

       
public class Result
       
{
           
public string Id { get; set; }

           
public string Class { get; set; }
           
public string School { get; set; }

Daniel Häfele

unread,
May 27, 2016, 11:04:41 AM5/27/16
to RavenDB - 2nd generation document database
You could also do it like this:

Map:
from student in docs.students
from classId in student.Classes
let @class = LoadDocument(classId)
select new 
{
    ClassId = classId,
    ClassName = @class.Name,
    School = @class.School,
    Count = 1
}

Reduce:
 from result in results
 group result by result.ClassId into g
 select new
 {
    ClassId = g.Key,
    ClassName = g.First().ClassName,
    School = g.First().School,
    Count = g.Sum(f => f.Count)
 }

Give it a try here: http://live-test.ravendb.net/studio/index.html#databases/query/index/Classes%2FWithStudentCount?&database=Students

Justin A

unread,
May 30, 2016, 3:12:08 AM5/30/16
to RavenDB - 2nd generation document database
@Daniel omg. BOOM! WORKS!!

(in fact, i ended up doing a 3x multi-map + reduce for my real work code).

wow so kewl!

thanks thanks thanks thanks thanks thanks thanks thanks thanks thanks thanks thanks thanks thanks thanks and thanks.

-memememe-
Reply all
Reply to author
Forward
0 new messages