And now let's go ahead and wrap up our search and our favorite query here. But just before we do that, I want to bring your attention to the fact that if I favorite a board and then have that inside of my user favorites and then if I go ahead and delete a board what will happen is that I have an existing user favorite but I don't have a proper relation with the board and that will in exchange cause an error. So if you've deleted a board while working on this user favorites here's what you can do. So every time inside of your database here you can always delete all documents. So you can just select, select all and delete all documents.
You can always do that quite easily inside of here. There we go like that. So let's make everything empty for now. Let's go ahead inside of our convexboard.ts and let's find our remove function and in here we actually have to do later check to delete favorite relation as well. So that's exactly what we're going to do.
We're going to go ahead here now and we're going to write const existing favorite and just before we do that, we can also get the user ID to be identity.subject so then inside of here, let's go ahead and write await context.database query user favorites like that with index and we're going to go ahead and use by user board Let me just quickly check the schema. So by user board exists. All right, so by user board, then we're going to go ahead and get the query. Then we can do query. Dot equals user ID to be user ID and equals boardId to be the arguments.id like that and let's go ahead and get unique from this combination and then I'm gonna write if existing favorite exists let's make sure to remove that relation so await context.database.delete existing favorite underscore ID like that.
So let's try that out now. So I'm going to go ahead and I'm going to create a new board here. So let me just confirm inside of here in my boards I have a new board and I don't have any user favorites here. Once I add this to my favorites I now have a user favorite and I have one board and if I go ahead and delete this board I should have empty user favorites and I do zero documents and zero boards. So we successfully fixed that issue.
Great! Now that we have that resolved let's go ahead and let's try one more thing. In our favorite function, I think we can speed up this query for existing favorite. I don't think we need to fetch by organization. So we can remove organization from here and simply use by user board and we can also safely then remove this comment here to do check if organization ID is needed.
I don't think we need that. If you notice that we do need it you can bring it back but I think that that query is not needed for us. This all seems to be in sync if I remove this both of this get removed. Perfect! So all of this seems to be working exactly as it should.
Let me just try this. Perfect. Okay. So now let's go ahead and let's actually implement that when we search for something we actually query by our search index which we have inside of our schema. So we have a search index here for the search title.
So in order to do that we have to go inside of our convex boards right here and we have to allow other arguments we have to allow arguments other than organization ID. So that's going to be search, which is going to be optional, and a type of string, like that. Perfect. So now let's go ahead and let's do the following here. We're going to add a constant for our search.
So const title is going to be arguments.search as string. Then we're going to go ahead and write let boards to be an empty array initially and we're gonna remove the constant from here. And this is what we're gonna do. If we have the title, we're gonna write to do query with search index, else we're gonna go ahead and query our boards as we usually would like this. So let's go ahead now and let's modify the boards here to now be await context.database we're gonna go ahead and query the boards but we're gonna use with search index this time search title we're gonna get the query and then we're going to do query dot search title and title but we are also only going to search inside of our organization ID which comes from the arguments as well and let's do .collect.
There we go! So now this should work just fine. The only thing that we are not passing is the search. So let's find where we have to pass that. Let's go inside of AppDashboardComponentsBoardList and do I have the queries here?
I do have all the queries here. So I think that we are pretty safe to simply write search query.search besides organization ID. So let's try that out now. I'm gonna go ahead and remove everything here and if I write untitled there we go you can see that I have untitled if I type something completely different we don't have that perfect so let me try renaming this to for example specific just specific if I type untitled it no longer exists if I type specific it exists Perfect. Our search is now officially working.
So now what I want to do is I want to do the same thing but allow it to be queried for favorites as well. So here's what we're gonna do. Let's go ahead and while we are inside of this board list instead of passing this individually we're just gonna spread the query like that and then let's go back inside of boards.ts and let's also add favorites to be v.optional and let's go ahead and mark this as v.any like this. Actually I think we can make it a string. Let me just check inside of board list.
This is a type of string. So let's make this a string then. Yes. All right. And now we have to do a similar thing.
So let's go ahead and go just before we check the identity let's do if args.favorites in that case we're gonna do const favorited boards are gonna be await context.database query user favorites database query user favorites we're going to use with index here by user and by organization that that user is in let's get the query and let's do query equals user ID to be identity dot subject and equals organization ID to be arguments dot organization ID and let's go ahead and order all of them by descending so the latest added to the favorite list and let's collect all of them. So this way we're gonna get all of the favorited boards and now let's go ahead and get all the IDs by using favoritedboards.map and let's go ahead and extract board ID sorry B underscore ID out of every one of those boards and now what we can do is we can install convex helpers so let's go ahead and do that so I'm gonna go ahead and shut down convex for now and let's do npm install convex-helpers like that Let's wait a second for this to install. And once it is ready, we're going to go ahead and do npm npx-convex-dev again.
So just make sure you have npm run dev running in one terminal and in another npx-convex-dev. And in here, I'm going to go ahead now and I'm going to import getAllOrThrow from convex helpers slash server slash relationships. Like that. So we don't have to write any complex queries here. Instead, what we can do is const boards to be await, get all or throw context.database and simply pass in the IDs as the second argument.
And then we can do boards.map, get the individual board, and let's go ahead and immediately return and spread the existing board and simply map is favorite to true. We don't need to do any calculation here. We know it's going to be true because we are only loading the words by the favorited words IDs right here. And I made a mistake here. So this will actually not give us the result we want.
So the list of IDs that I wanted to make was the list of relationships inside of our schema. You can see how I actually have an error here. So this tells me that this doesn't exist. That's because I'm supposed to use board ID here. And there we go.
Once I change this to board ID, this will actually load the boards. And now you can see that this is favorite will still exist. So Let's try it out now. So if I click on favorite boards, it says no favorite boards. Try favoriting a board.
If I add this to my favorite boards and click here, there we go. If I remove it from here, it no longer exists. Perfect. So let's try this with a couple of more elements here. So I'm going to randomly add a couple of them.
There we go. So only they appear here. Perfect. Let's go ahead and try searching for something that should bring us back to the theme boards. Let's be more specific.
That still seems to be working just fine. Perfect. Amazing, amazing job. You just added a complete search, querying and everything that we need here. And what we are finally ready to do next is build this actual screen which will happen when we click on that.
But just before we do that we can already prepare ourselves by doing this. So let's find everywhere where we use API board create. So we have that in two files in empty boards component in app dashboard underscore components and the new board button. So let's go in empty boards first. Let's see where it's located app folder dashboard components, empty board.
So we can now actually do this redirect right here, right? We know how it's gonna look like. So const router, use router from next navigation. I'm just gonna move that right here. And what I'm gonna do now is do router.push board, and I'm gonna pass in that specific ID like that.
And I can remove the to do comment. And the other one, which we had, let's see if we have another one, new board button. So this one is located in the same place, I believe. So app dashboard underscore components, new board button. So in here we have the same thing.
Let's go ahead and get our router here. Const router, use router from next navigation. So just ensure you're using next navigation here and let's just try that out. So now every time that we create a new board we should get redirected to the currently 404 page which in a next chapter is gonna start looking like an actual board so let me just go ahead and remove all of my elements here so we can confirm that it is actually working from that empty screen as well we confirmed that the button works, but how about this one? Same thing, it works.
Perfect. Great, great job.