Search & filter
I have the code below, but i seem to be getting an error on the args.name
Property 'withSearchIndex' does not exist on type
31 Replies
You can't apply multiple indexes - you're using
withIndex()
before the conditionals.
you can add locationId
as a filter field on your search index if you want to effectively have these two indexes combined, but you'll still need to not run withIndex()
before withSearchIndex()
, either one or the other.what would you advise i do...i dont understand when you say combine... an still not run withIndex.. I just picked up convex and im liking it so far
Ah, welcome to the Convex community!
So you're initially defining
partsQuery
using .withIndex()
. Once you use withIndex()
or withSearchIndex()
, the object you get back no longer has the withIndex()
or withSearchIndex()
methods.
I would honestly just write the whole query in each conditional rather than trying to initialize at the top and then extend conditionally. Here's what that looks like:
You are godlike... thank you
Your original also had
{ searchField: 'name' }
- that belongs in the schema definition
Going beyond your original question, understand that filter()
does not limit the number of rows scanned, so you'll want to index instead of filter wherever possible. For the code you pasted, you can replace both filters with indexes. I'll give an example of that too.
Actually I'm curious if kapa (ai bot in the discord here) can rewrite this, going to try thatIm checking the code you sent, it doesnt seem that i can query both machineclass and factory at the same time... the current logic is at any time i can search for either the machineclass or factory or both
yep, kapa found that lol, I didn't catch that you were conditionally applying both filters
this is my current schema
Yeah that was the goal
alright, one sec
your query has all args required - are any of them optional?
Guessing locationId is required and the others are optional
args: {
locationId: v.id("locations"),
factoryId: v.optional(v.id("factories")),
machineClassId: v.optional(v.id("machineClasses")),
name: v.optional(v.string()),
},
This is lengthy but it lays things out in an obvious way. I would advocate for letting code be lengthy while you're getting the hang of Convex, and going back to optimize / dry once things are flowing.
Here's the schema with additional indexes:
Thank you so much for the code... really means a lot.. im slowly but surely understanding things as they go
For sure. You'll want to utilizing indexes as much as possible so each query is scanning the smallest possible amount of rows, keeps things snappy.
oh okay... i think i understand
Looks like there's an error around search index uniqueness, looking at that now
ah right, you can only search index on a given field once per table
hmm
yeah
was just about to say that
Playing with combining the filters now - I believe they have to be in order, which would make
undefined
a value in the index for missing fields, but that isn't what you want
But maybe that's not the case, confirming
That can replace the three args.name
queries
And you can drop the other search indexes
Working:
Some gotchas to point out:
- "filter" when querying with a regular index does not limit the rows scanned
- "filterFields", defined in a search index, do limit the rows scanned
- when working with a regular index, queries must match indexed fields in the order they're defined in the schema, and cannot skip fields (so q.eq('field1', field1).eq('field3', field3)
doesn't work if the index is defined as .index('by_field', ['field1', 'field2', 'field3'])
because field2
is skipped)
- when working with the filter fields against a search index, queries can use search.eq()
to reference any of the filter fields in any orderthis is amazing.. i think i get it... you are amazing.. thanks for taking the time to explain
No problem! Convex is the bees knees, I hope you love it. Reach out here in support if you get stuck or have questions 👍
@erquhart Hello chief, been wondering what is the quickest way to get data from an external id...for instance this query.. this query returns the machineClassId... i want to be able to get the info from the id
You'll map/loop over the data to get related data - this is how joins work in Convex:
Relevant docs: https://docs.convex.dev/database/reading-data#join
Reading Data | Convex Developer Hub
Query and
@erquhart thanks as always...
another confusing thing has to be pagination
on how to use the usePaginatedQuery
No problem! Did you see the docs on paginated queries?
Module: react | Convex Developer Hub
Tools to integrate Convex into React applications.
yeah i did
const { results, status, isLoading, loadMore } = usePaginatedQuery(
api.messages.list,
{ channel: "#general" },
{ initialNumItems: 5 }
);
i already have the query you sent me...
it was how to integrate it that became the issue
this is what my query looks like now, i want to know if this is ideal
i cant paste the full code because discord wouldnt allow me
but im having an issue when trying to query
im getting Types of property _returnType are incompatible.
when calling it like this
@erquhart id appreciate your feedback when you are less busy.... apologies for the disturbances
hey! no problem at all, notifications don't hit me unless I want them to
catching up on your messages now
Yeah,
.paginate()
returns a result object - is typescript not showing you errors in the convex function you pasted above?
oh nvm you're hitting parts.page
, that's correct
missed that
hmm what is it saying are the two incompatible return types
oh hmm you're calling paginate twice in the same convex function, that won't work
I'm not coming up with a better way than using two separate query functions here, one with machineClassId and one without.
When the team comes online they may have a way to do it better, but I can't think of one.
Although as long as the arguments don't change I feel like what you have should work, as it would consistently hit the same conditional. If you can share the error that would help illuminate a bit.i am confused about the calling pagination twice part
@erquhart this is the error
Argument of type 'FunctionReference<"query", "public", { factoryId?: Id<"factories"> | undefined; machineClassId?: Id<"machineClasses"> | undefined; name?: string | undefined; locationId: Id<"locations">; paginationOpts: { ...; }; }, { ...; }[]>' is not assignable to parameter of type 'PaginatedQueryReference'.
Types of property '_returnType' are incompatible.
Type '{ machineClass: { _id: Id<"machineClasses">; _creationTime: number; name: string; factory: Id<"factories">; } | null; _id: Id<"parts">; _creationTime: number; factoryId: Id<"factories">; ... 4 more ...; weight: number; }[]' is missing the following properties from type 'PaginationResult<any>': page, isDone, continueCursor
this is how i am calling it
const { results, status, loadMore } = usePaginatedQuery(api.parts.getParts, {
locationId: activeLocation as Id<'locations'>,
factoryId,
machineClassId,
name,
}, {
initialNumItems: 5
});
oh right
Your paginated query has to return the object you received from
.paginate()
, it includes the cursor
You can still manipulate the items in the page array as you're doing, but the function ultimately needs to return the whole result object
Your query should work fine with just that change, but if the args change it will reset pagination. I believe that's the only thing to be aware of there.
Pretty sure changes in args always resets pagination anyway, but I could be wrong, it may adapt. Can't recall atm
But, if a call to your paginated query triggers one of those .paginate()
calls, and then a change in the args leads to the other .paginate()
being called, that will either cause an error, odd behavior, or just reset the pagination. Again, team will know for sure.thanks.. ill definitely keep that in mind
Helpful answer from kapa has some relevant links: https://discord.com/channels/1019350475847499849/1237752632483774514