Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

findByIds Deprecated #61

Open
csandoval18 opened this issue Aug 11, 2022 · 1 comment
Open

findByIds Deprecated #61

csandoval18 opened this issue Aug 11, 2022 · 1 comment

Comments

@csandoval18
Copy link

csandoval18 commented Aug 11, 2022

I'm in minute 11:36:00 of the tutorial, and I noticed that findById was deprecated when implementing the createUserLoader function. I was able to get around it by doing the following:

export const createUserLoader = () =>
	new DataLoader<number, Users>(async (userIds) => {
		const users = await Users.findBy({ id: In(userIds as number[]) })
		const userIdToUser: Record<number, Users> = {}
		users.forEach((u) => {
			userIdToUser[u.id] = u
		})

		const sortedUsers = userIds.map((userId) => userIdToUser[userId])
		return sortedUsers
	})

As you can see I used findBy instead of findByIds and the In function provided by typeorm. I tried using the same approach for the createUpdootLoader, but I noticed that it did not work since I needed to search for both the userId and the postId to retrieve the corresponding upvotes. Was anyone able to implement that correctly? I am unsure how to use findBy to search multiple fields with the keys since I cannot seem to separate the key fields by using keys.userId and keys.postId. This is my current code:

export const createUpdootLoader = () =>
	new DataLoader<{ postId: number; userId: number }, Updoot | null>(
		async (keys) => {
			console.log('keys:', keys)
			const updoots = await Updoot.findby({userId:  In(keys as any} )
			const updootIdsToUpdoot: Record<string, Upvotes> = {}
			updoots.forEach((updoot) => {
				upvoteIdsToUpvote[`${updoot.userId} | ${updoot.postId}`] = updoot
			})

			const sortedUpdoot = keys.map(
				(key) => updootIdsToUpdoot[`${key.userId} | ${key.postId}`],
			)
			return sortedUpdoots
		},
@Adeniyii
Copy link

Adeniyii commented Aug 29, 2022

Hey @csandoval18 , here's how I was able to solve it, though I'm not 100% sure it's the right approach.

Basically, I map over the list of key-value objects to extract the userIds and postIds into separate arrays. Then apply them as separate search criteria in the findBy function. After that, I generate an updootToIdMap with the key as a string of format: <postId>|<userId> and the value as a returned updoot. Finally, I return the array of updoots in the same order the initial object array idObjArr was provided.

Hope this helps!

import DataLoader from "dataloader";
import { In } from "typeorm";
import { Updoot } from "../entities/Updoot";

// A data loader takes a list of keys (in this instance, a list of objects of keys),
// and returns a list of corresponding entities - updoots | null in the same order as the given keys.
// Data loaders batch and cache database requests to avoid the N + 1 problem of
// fetching N requests for a single db query
export const createUpdootLoader = () => new DataLoader<{userId: number, postId: number}, Updoot | null>(async (idObjArr) => {
	const userIds = idObjArr.map(obj => obj.userId)
	const postIds = idObjArr.map(obj => obj.postId)
	const updoots = await Updoot.findBy({userId: In(userIds), postId: In(postIds)})

	const updootToIdMap: Record<string, Updoot> = {}
	updoots.forEach(updoot => {
		updootToIdMap[`${updoot.postId}|${updoot.userId}`] = updoot
	})

	return idObjArr.map(obj => {
		return updootToIdMap[`${obj.postId}|${obj.userId}`];
	})
})

This is the SQL that was generated when the loader is executed.

dootsql

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants