🕰️ Chapters
- Querying Total Movie Count
- Creating A Stat Component
- Querying Writer & Director Counts
- Converting Counts to Numbers
- Counting Total Watched Movies
Counting Stats for our Admin Dashboard
In this lesson, we'll perform various counts against our models to display on our admin dashboard page.
- Author
- Tom Gobich
- Published
- Jun 06
- Duration
- 5m 43s
![Tom Gobich](/img/1/profile/avatar_1703713552864.jpg)
Developer, dog lover, and burrito eater. Currently teaching AdonisJS, a fully featured NodeJS framework, and running Adocasts where I post new lessons weekly. Professionally, I work with JavaScript, .Net C#, and SQL Server.
Adocasts
Burlington, KY
Transcript
Counting Stats for our Admin Dashboard
-
[MUSIC]
-
So what good is an admin dashboard if we're not doing
-
some form of an aggregation to
-
show our administrators how we're doing?
-
So let's aggregate some numbers,
-
maybe like our total movie count,
-
user count, and the like to show on our dashboard.
-
So we can go back into our dashboard
-
controller and start aggregating.
-
So first, let's go and just do our total movie counts.
-
We'll do const movieCount equals weight,
-
and we can use our movie model to query.count,
-
and let's just count the ID column as that
-
will uniquely identify the movie.
-
Now, this will return back an array,
-
and then the movie count will be inside of
-
the first array index extras object.
-
So what we can do is just grab the first or fail there,
-
and that will allow us to just do moviesCount.extras.
-
Let's give this, say,
-
an alias of count so that we can just do.count.
-
Let's provide that into our page state.
-
So moviesCount.
-
Okay, let's make both of those names match.
-
There we go. Jump on down to our dashboard page,
-
and let's do div class flex items center justify around,
-
add a gap of four,
-
and let's also let these wrap.
-
So we can do flex wrap too.
-
Let's do now another div class flex flex call div class text extra large,
-
and this is where our number will go,
-
and then we'll have a div class text slate,
-
maybe 400 text extra small,
-
font bold, and this is where our label will go.
-
Actually, let's make this just LG rather than extra large.
-
So that we're not copying and pasting this for each stat that we do,
-
we can scroll on down to our components,
-
right-click that, new file,
-
and we do a stat folder with an index.edge inside of it,
-
and we can now paste that inside of here.
-
Inside of our number div,
-
we can now do value.to local string,
-
and then we can do label for our label.
-
Jump back into our dashboard,
-
and we can now get rid of that,
-
and just do @stat label total movies value is our moviesCount.extras.
-
It should be named count.
-
This is a self-closing text,
-
we also need to add an exclamation point there to assert that.
-
Cool. So let's go and jump into our browser and see what we have.
-
Cool. So it looks like we have 420 total movies.
-
If you really wanted to,
-
you could also jump into your dashboard controller,
-
filter down these individually by released,
-
not yet released, releasing soon,
-
or just generally by the overall status of the movie as well.
-
Let's also grab our writers and directors counts.
-
So writers count equals await,
-
and this will want to reach for our Cineasts model,
-
query where has movies written,
-
and this expects just a query callback of some sort,
-
but we don't need to filter that down any further.
-
So we'll just leave that as is.
-
We can give that a copy,
-
paste that one more time for our directors count,
-
and instead of where has movies written,
-
this will be where has movies directed.
-
Let's add that into our page state as well.
-
So writers count and directors count, just like so.
-
Jump into our dashboard page,
-
give this stat here a copy and a paste two times,
-
total writers and total directors.
-
And then this will be our writers count,
-
and this will be directors count.
-
If that is saved, we can check that out in the browser now.
-
And cannot read properties of undefined reading count.
-
Oh yeah, no, we forgot to count it all together.
-
My bad.
-
Okay, dashboard controller.
-
We just did the where has.
-
What we need to do now after the where has
-
is also counted by the Cineasts ID.
-
There we go.
-
And then we'll also want to do first or default
-
where has count ID dot first or fail.
-
Cool. All right.
-
Let's go give that a test one more time.
-
So jump back in here, refresh.
-
There we go.
-
We have 420 movies, 109 writers, and 108 directors.
-
Now within our stat, we did two local string,
-
but I think these are probably already coming through
-
as string and our intention there was to format.
-
So let's go jump back into our stat here
-
and I'm just gonna do a quick type of value
-
and let's get rid of the two local string here momentarily
-
just to see what this is coming through as.
-
I bet you it's a string.
-
Yep, sure is.
-
Okay.
-
So let's switch this to parse int value
-
and we'll default that to zero if it's not provided.
-
And then we'll convert it to a local string.
-
And of course we can get rid of our type of there as well.
-
And what this two local string is doing is
-
let's say we had something like 1500 as our number.
-
It's going to take that number
-
and it'll convert it into a legible string.
-
So it's adding in the comma there for us.
-
So that's our intention with that.
-
Furthermore, if all of our counts are gonna come through
-
as extras dot count,
-
we can go ahead and normalize that altogether as well
-
by just moving that into our stat component.
-
That is completely up to you.
-
And that is a design decision.
-
We'll go ahead and move forward with it here
-
because all of ours should match that.
-
So it'll just simplify things a little bit here for us.
-
Give that a save and let's double check everything.
-
I think this error is from before
-
we actually saved the dashboard page.
-
Let's give it a refresh for sanity sake.
-
And sure enough, it was.
-
Okay, cool.
-
Hide that back away.
-
All right.
-
So we should have a pretty good premise
-
on how we can count overall items.
-
So we'll leave users out here and move onward.
-
So let's go ahead and now count
-
the total number of movies watched.
-
So for this, we can do const watched movies count
-
equals await.
-
And we can reach for our watch list
-
as that's what discerns that query.
-
Where not null watched at.
-
Go ahead and count the ID of our watch lists
-
as we can only ever have one watch list per user per movie.
-
So that should be distinct.
-
And then we can do first or default to keep with our theme.
-
And it does look like the default name for count is count
-
as our directors and writers count have been working.
-
So we can go ahead and get rid of the alias here as well.
-
And then let's add our movies watch list count
-
into our page state.
-
So watched movies count.
-
Jump into our dashboard and we can do at stat label
-
movies watched value watch movies count.
-
Give that a save.
-
And let's go check that out real quick.
-
There we go.
-
So six movies have been watched out of a total
-
of 420 movies that we have comprised of 108 total writers
-
and 109 total directors.
-
I did that backwards.
-
109 total writers and 108 total directors.
-
Introduction
-
Fundamentals
-
2.0Routes and How To Create Them5m 24s
-
2.1Rendering a View for a Route6m 30s
-
2.2Linking Between Routes7m 52s
-
2.3Loading A Movie Using Route Parameters9m 18s
-
2.4Validating Route Parameters6m 7s
-
2.5Vite and Our Assets6m 39s
-
2.6Setting Up Tailwind CSS7m 5s
-
2.7Reading and Supporting Markdown Content4m 32s
-
2.8Listing Movies from their Markdown Files8m 51s
-
2.9Extracting Reusable Code with Services7m 4s
-
2.10Cleaning Up Routes with Controllers4m 52s
-
2.11Defining A Structure for our Movie using Models9m 38s
-
2.12Singleton Services and the Idea of Caching6m 11s
-
2.13Environment Variables and their Validation4m 16s
-
2.14Improved Caching with Redis10m 44s
-
2.15Deleting Items and Flushing our Redis Cache6m 46s
-
2.16Quick Start Apps with Custom Starter Kits6m 28s
-
2.17Easy Imports with NodeJS Subpath Imports8m 40s
-
-
Building Views with EdgeJS
-
3.0EdgeJS Templating Basics8m 49s
-
3.1HTML Attribute and Class Utilities6m 9s
-
3.2Making A Reusable Movie Card Component10m 24s
-
3.3Component Tags, State, and Props4m 53s
-
3.4Use Slots To Make A Button Component6m 56s
-
3.5Extracting A Layout Component5m 13s
-
3.6State vs Share Data Flow2m 59s
-
3.7Share vs Global Data Flow6m 8s
-
3.8Form Basics and CSRF Protection6m 13s
-
3.9HTTP Method Spoofing HTML Forms3m 3s
-
3.10Easy SVG Icons with Edge Iconify7m 57s
-
-
Database and Lucid ORM Basics
-
4.0Configuring Lucid and our Database Connection4m 3s
-
4.1Understanding our Database Schema9m 35s
-
4.2Introducing and Defining Database Migrations18m 35s
-
4.3The Flow of Migrations8m 28s
-
4.4Introducing Lucid Models5m 43s
-
4.5Defining Our Models6m 49s
-
4.6The Basics of CRUD11m 56s
-
4.7Defining Required Data with Seeders11m 11s
-
4.8Stubbing Fake Data with Model Factories13m 48s
-
4.9Querying Our Movies with the Query Builder15m 30s
-
4.10Unmapped and Computed Model Properties3m 24s
-
4.11Altering Tables with Migrations7m 6s
-
4.12Adding A Profile Model, Migration, Factory, and Controller2m 57s
-
4.13SQL Parameters and Injection Protection9m 19s
-
4.14Reusable Query Statements with Model Query Scopes8m 11s
-
4.15Tapping into Model Factory States9m 15s
-
4.16Querying Recently Released and Coming Soon Movies4m 59s
-
4.17Generating A Unique Movie Slug With Model Hooks7m 59s
-
-
Lucid ORM Relationships
-
5.0Defining One to One Relationships Within Lucid Models5m 49s
-
5.1Model Factory Relationships2m 54s
-
5.2Querying Relationships and Eager Vs Lazy Loading5m 17s
-
5.3Cascading and Deleting Model Relationships5m 16s
-
5.4Defining One to Many Relationships with Lucid Models6m 56s
-
5.5Seeding Movies with One to Many Model Factory Relationships5m 24s
-
5.6Listing A Director's Movies with Relationship Existence Queries8m 41s
-
5.7Listing and Counting a Writer's Movies8m 41s
-
5.8Using Eager and Lazy Loading to Load A Movie's Writer and Director5m 18s
-
5.9Defining Many-To-Many Relationships and Pivot Columns9m 48s
-
5.10Many-To-Many Model Factory Relationships4m 50s
-
5.11A Deep Dive Into Relationship CRUD with Models18m 5s
-
5.12How To Create Factory Relationships from a Pool of Data13m 55s
-
5.13How To Query, Sort, and Filter by Pivot Table Data9m 47s
-
-
Working With Forms
-
6.0Accepting Form Data12m 15s
-
6.1Validating Form Data with VineJS9m 29s
-
6.2Displaying Validation Errors and Validating from our Request7m 16s
-
6.3Reusing Old Form Values After A Validation Error2m 3s
-
6.4Creating An EdgeJS Form Input Component5m 28s
-
6.5Creating A Login Form and Validator5m 1s
-
6.6How To Create A Custom VineJS Validation Rule9m 7s
-
-
Authentication & Middleware
-
7.0The Flow of Middleware7m 49s
-
7.1Authenticating A Newly Registered User4m 14s
-
7.2Checking For and Populating an Authenticated User2m 10s
-
7.3Logging Out An Authenticated User2m 24s
-
7.4Logging In An Existing User6m 54s
-
7.5Remembering A User's Authenticated Session6m 55s
-
7.6Protecting Routes with Auth, Guest, and Admin Middleware5m 36s
-
-
Filtering and Paginating Queries
-
8.0Creating A Movie List Page3m 43s
-
8.1Filtering A Query By Pattern Likeness7m 9s
-
8.2Filtering Our List by Movie Status5m 47s
-
8.3How To Apply A Dynamic Sort Filter To Your Query7m 12s
-
8.4Joining SQL Tables To Order By A Related Column4m 49s
-
8.5Validating Query String Filter Values7m 24s
-
8.6How To Paginate Filtered Query Results9m 15s
-
8.7Pagination First, Last, Next, and Previous Buttons4m 3s
-
-
User Watchlist
-
9.0An Alternative Approach to Many-To-Many Relationships4m 56s
-
9.1Toggling A Movie in an Authenticated User's Watchlist9m 56s
-
9.2Listing and Filtering User Watchlist Items7m 31s
-
9.3Allowing Users To Toggle A Movie As Watched4m 44s
-
9.4Filtering By User's Watched Status6m 7s
-
9.5Defining A Composite Unique Constraint4m 47s
-
9.6Persist Filters Easily with Lucid's Query String Method3m 58s
-
-
User Profiles
-
10.0How to Create and Fix Missing User Profiles in Your Application7m 37s
-
10.1Using Dependency Injection to Update A User's Profile9m 46s
-
10.2Saving All Or Nothing with Database Transactions5m 15s
-
10.3Uploading and Displaying User Avatars15m 29s
-
10.4Displaying A User's Profile6m 1s
-
10.5Filtering, Preloading, and Sorting By Relationship7m 6s
-
-
Admin Panel
-
11.0Creating An Admin Layout7m 14s
-
11.1Counting Stats for our Admin Dashboard5m 43s
-
11.2Paginated Admin Movie Table13m 2s
-
11.3Allowing Admins to Create Movies16m 39s
-
11.4Allowing Admins to Update Movies and Clear Values13m 27s
-
11.5How To Use One Form to Create or Edit Movies5m 32s
-
Uploading Movie Cover Images in our Create or Edit Form10m 29s
-
Using A Wildcard Route Param to Download Storage Images7m 57s
-
Posting Objects, Arrays, and an Array of Objects in HTML Forms26m 26s
-
Managed Transactions and Syncing Movie Cast Members15m 55s
-
Allowing Admins to Delete Movies and their Relationships7m 42s
-
Thank You for Watching!0m 31s
-
Join The Discussion! (0 Comments)
Please sign in or sign up for free to join in on the dicussion.
Be the first to Comment!