Developer forum

Forum » Templates » LINQ 'nested' GroupBy

LINQ 'nested' GroupBy

Jens Mouritzen
Jens Mouritzen
Reply

Hi guys

We got an event calendar where we would like to 'nest' the grouping of items in the current order:
 

  • Weekday
    • Venue
      • Artist
      • Artist
      • Artist
    • Venue
      • Artist
      • Artist

We got the following code (current.jpg) made with LINQ but we are struggeling to make the above nesting (desired.jpg)

Any ideas on how we can 'nest' this LINQ?

Below is the code we got so far:

@using System;

@using System.Collections.Generic;

@using System.Linq;



@inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 



@{

 var items = GetLoop("ItemPublisher:Items.List")

 .SelectMany(item => item.GetLoop("ItemPublisher:Item.WhenAndWhere")


    .Select(artist => new {

      date = artist.GetDate("ItemPublisher:Item.WhenAndWhere.Date"),

      title = item.GetString("ItemPublisher:Item.Title"),

      image = item.GetString("ItemPublisher:Item.Image"),

      focal = item.GetString("ItemPublisher:Item.Image.FocalPointParameters"),

      link = item.GetString("ItemPublisher:Item.Url"),

      venue = artist.GetString("ItemPublisher:Item.WhenAndWhere.Where")

 }))


    .OrderBy(item => item.date)

 .GroupBy(item => item.date.ToString("dddd"))


    .Select(group => new {

 Day = group.Key,

 Events = group

 });

 

}


<div class="grid">

 @foreach (var item in items) {

  

 <div class="grid__col-md-12">

 <h3 class="u-no-margin">@item.Day</h3>

   </div>

  

   <div class="grid__col-md-12">

          <div class="grid">

            

         @foreach(var e in item.Events){

              <div class="grid__col-md-12">

                <div class="u-flex">

                  <div class="u-flex grid--align-start grid--direction-column grid--justify-center">

                    <h5 class="u-no-margin">@e.title @e.venue @e.date.ToString("'kl' HH:mm")</h5>

                  </div>

                </div>

              </div>

         }

          </div>

   </div>


 }

</div>
current.png desired.png

Replies

 
Claus Kølbæk
Claus Kølbæk
Reply

Hey Jens

Can't you just do OrderBy Venue ThenBy Artist?

 
Jens Mouritzen
Jens Mouritzen
Reply

Hi Claus
My LINQ skills are pretty limited and i'm still learning this.
Would you mind giving an example with the above code? 

 
Claus Kølbæk
Claus Kølbæk
Reply

I would possibly just do something like this:

@foreach(var in in GetLoop("ItemPublisher:Items.List").OrderBy(x => x.GetDate("ItemPublisher:Item.WhenAndWhere.Date").DayOfWeek).ThenBy(x => x.GetString("ItemPublisher:Item.WhenAndWhere.Where")).ThenBy( x=> x..GetString("ItemPublisher:Item.Title"))){

...

}

Not really sure if title is the right pick for your "Artist" but you can prob. figure out the idea from it :) It can be prettied up a bit if you like. - also you can do the grouping thing in multiple ways but the quick and dirty I think would just be to do save a string with the last used day - and then if it changes you write in your new headline, and overwrite your save (this will work because its already sorted).

 
Jens Mouritzen
Jens Mouritzen
Reply

Hi Claus
It's not just a matter of ordering the items, they need to be grouped as well.

The items are like this: each item is called Artist. The artist has a loop where the loop items contains a date and where (venue) field.
I need to group the items into weekdays, then Venue, and then the Artist name.

Like the image attached. I really hope you can help smiley

desired.png
 
Claus Kølbæk
Claus Kølbæk
Reply

Hey Jens

I get that, but by sorting by weekdays first, you escentially have created a group if you simply check when the week day is different.

so a short example:

var lastWeekday = "";

var lastVenue = "";

for(var i in sortedList){

   if(i.currentWeekday != lastWeekday){

      <h2>i.currentWeekday</h2>

      lastWeekday = i.currentWeekday;

   }

if(i.currentVenue != lastVenue ){

      <h2>i.currentVenue </h2>

      lastVenue = i.currentVenue ;

   }

<p>@i.currentArtistName</p>

}

The above works because you have already sorted the list first on weekday (see my earlier comment on OrderBy and then By)

Its just a simple way of achieving the grouping function that works due to a relativ none complex dataset. - as I said, not the prettiest but it works :)

 
Jens Mouritzen
Jens Mouritzen
Reply

Hi Claus
Interesting. I now got this code with the example you made:
 

@inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 


@using System;

@using System.Collections.Generic;

@using System.Linq;



@{


    string lastWeekday = "";

    string lastVenue = "";


 var items = GetLoop("ItemPublisher:Items.List")

 .OrderBy(x => x.GetDate("ItemPublisher:Item.WhenAndWhere.Date"))

 .ThenBy(x => x.GetString("ItemPublisher:Item.WhenAndWhere.Where"))

 .ThenBy( x => x.GetString("ItemPublisher:Item.Title"));

}


<div class="grid">


 @foreach (var item in items) {


     var title = item.GetString("ItemPublisher:Item.Title");

     string currentWeekDay = "";

     string currentWeekDayValue = "";

     string currentVenue = "";

  

   foreach (var day in item.GetLoop("ItemPublisher:Item.WhenAndWhere"))

     {

   currentWeekDay = day.GetDate("ItemPublisher:Item.WhenAndWhere.Date").ToString("dddd");

   currentWeekDayValue = day.GetDate("ItemPublisher:Item.WhenAndWhere.Date").ToString();

   currentVenue = day.GetString("ItemPublisher:Item.WhenAndWhere.Where");

     }

  

      <div class="grid__col-md-12">

        

 @if(currentWeekDay != lastWeekday)

 {

 <h1 class="day">@currentWeekDay</h1>

  

 lastWeekday = currentWeekDay;

  

 }

        

 @if(currentVenue != lastVenue)

 {

 <h2 class="venue">@currentVenue</h2>

  

 lastVenue = currentVenue;

  

 }

        

       <p class="artist">@title</p>

      </div>

  

 }

</div>

 

This gives the current result (image attached). I cant find the "error" that gives the multiple days output. 

2019-06-17_22_55_00-Program_–_Google_Chrome.png
 
Claus Kølbæk
Claus Kølbæk
Reply

 var items = GetLoop("ItemPublisher:Items.List")
    .OrderBy(x => x.GetDate("ItemPublisher:Item.WhenAndWhere.Date"))
    .ThenBy(x => x.GetString("ItemPublisher:Item.WhenAndWhere.Where"))
    .ThenBy(x => x.GetString("ItemPublisher:Item.Title"));

In the above your are ordering by date - not by day of week; should prob. be changed to something like:

 var items = GetLoop("ItemPublisher:Items.List")
    .OrderBy(x => x.GetDate("ItemPublisher:Item.WhenAndWhere.Date").DayOfWeek)
    .ThenBy(x => x.GetString("ItemPublisher:Item.WhenAndWhere.Where"))
    .ThenBy(x => x.GetString("ItemPublisher:Item.Title"));

Also I don't really get this extra foreach you have in the middle of everything?:

 foreach(var day in item.GetLoop("ItemPublisher:Item.WhenAndWhere")) {
            currentWeekDay = day.GetDate("ItemPublisher:Item.WhenAndWhere.Date").ToString("dddd");
            currentWeekDayValue = day.GetDate("ItemPublisher:Item.WhenAndWhere.Date").ToString();
            currentVenue = day.GetString("ItemPublisher:Item.WhenAndWhere.Where");
        }

Can't it just be:

 var title = item.GetString("ItemPublisher:Item.Title");
        string currentWeekDay = item.GetDate("ItemPublisher:Item.WhenAndWhere.Date").ToString("dddd");
        string currentWeekDayValue = item.GetDate("ItemPublisher:Item.WhenAndWhere.Date").ToString();
        string currentVenue = item.GetString("ItemPublisher:Item.WhenAndWhere.Where");

and then completely remove the extra foreach?

 
Jens Mouritzen
Jens Mouritzen
Reply

The "extra" foreach is to call the fields in the loop "WhenAndWhere" (artist's gig dates) in the "Items.List" loop. As far as i know this cant be done otherwise, right?

 
Claus Kølbæk
Claus Kølbæk
Reply

I think you are doing it already without the foreach in the Linq, so I would assume you can.? But anyways, I think if you just add the day of week thing, then it will solve your issue.

 
Jens Mouritzen
Jens Mouritzen
Reply

I tried it without the foreach loop, and it gave me an empty string like 00:00:00.
I added the DayOfWeek to the string and now it looks like this: https://godtfolk.dk/Default.aspx?ID=2206

 

You must be logged in to post in the forum