Last active
February 15, 2024 17:28
-
-
Save kyldvs/98aed78f96e9376b55092493a8bb0b75 to your computer and use it in GitHub Desktop.
join on fields between convex tables
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { DataModel, Doc, Id, TableNames } from "./_generated/dataModel"; | |
import { GenericDatabaseReader, GenericDatabaseWriter } from "convex/server"; | |
type Database = | |
| GenericDatabaseReader<DataModel> | |
| GenericDatabaseWriter<DataModel>; | |
type DocWithId< | |
Table extends TableNames, | |
Relation extends TableNames, | |
> = Doc<Table> & { [key in `${Relation}Id`]: Id<Relation> }; | |
type Joined< | |
Table extends TableNames, | |
Relation extends TableNames, | |
> = Doc<Table> & { | |
[key in Relation]: Doc<Relation> | undefined; | |
}; | |
function nonNullable<T>(a: T): a is NonNullable<T> { | |
return a != null; | |
} | |
/** | |
* Joins two tables on the given field, example: | |
* | |
* // This has { _id: Id<"orgRole">, orgId: Id<"org">, ... } | |
* const roles = await ctx.db.query("orgRole").collect(); | |
* | |
* // This has { _id: Id<"orgRole">, org: Doc<"org"> | undefined, ... } | |
* const data = await join<"orgRole", "org">(ctx.db, roles, "orgId"); | |
*/ | |
export async function join< | |
BaseTable extends TableNames = never, | |
JoinTable extends TableNames = never, | |
>( | |
db: Database, | |
items: DocWithId<BaseTable, JoinTable>[], | |
field: `${JoinTable}Id`, | |
): Promise<Joined<BaseTable, JoinTable>[]> { | |
const ids = new Set(items.map((item) => item[field])); | |
const docs = await Promise.all(Array.from(ids).map((id) => db.get(id))); | |
const docMap = new Map(docs.filter(nonNullable).map((doc) => [doc._id, doc])); | |
const targetField = field.slice(0, -2) as JoinTable; | |
const result = items.map((item) => { | |
return { | |
...item, | |
[targetField]: docMap.get(item[field]), | |
}; | |
}); | |
return result; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment