Prisma — user.tasksAssigned Examples
Practical Prisma query patterns for retrieving and working with tasks assigned to a user. Optimized for AI assistant usage.
Prisma — user.tasksAssigned
Examples
These examples demonstrate idiomatic Prisma queries using the user.tasksAssigned
relation introduced in our schema. They cover common patterns such as filtering, pagination, counting, and eager-loading related records.
Import the shared Prisma client:
import { prisma } from "@/lib/prisma";
Basic: load tasks assigned to a user
export async function getUserTasks(userId: string) {
const user = await prisma.user.findUnique({
where: { id: userId },
select: {
id: true,
name: true,
tasksAssigned: true,
},
});
return user?.tasksAssigned ?? [];
}
Filter and sort: only open tasks ordered by sortIndex
export async function getOpenTasks(userId: string) {
const user = await prisma.user.findUnique({
where: { id: userId },
select: {
tasksAssigned: {
where: { status: "open" },
orderBy: [{ sortIndex: "asc" }, { createdAt: "asc" }],
},
},
});
return user?.tasksAssigned ?? [];
}
Include related Ticket details for each Task
export async function getTasksWithTicket(userId: string) {
const user = await prisma.user.findUnique({
where: { id: userId },
select: {
tasksAssigned: {
include: {
ticket: {
select: {
id: true,
title: true,
status: true,
priority: true,
project: { select: { id: true, name: true } },
},
},
},
},
},
});
return user?.tasksAssigned ?? [];
}
Pagination with cursor
interface GetUserTasksPageParams {
userId: string;
limit?: number;
cursor?: string; // task.id
status?: string; // e.g. "open", "closed"
}
export async function getUserTasksPage(params: GetUserTasksPageParams) {
const { userId, limit = 20, cursor, status } = params;
const tasks = await prisma.task.findMany({
where: { assigneeId: userId, ...(status ? { status } : {}) },
include: {
ticket: { select: { id: true, title: true, status: true, projectId: true } },
},
take: limit + 1,
...(cursor ? { cursor: { id: cursor }, skip: 1 } : {}),
orderBy: [{ sortIndex: "asc" }, { createdAt: "desc" }],
});
const hasMore = tasks.length > limit;
const items = hasMore ? tasks.slice(0, -1) : tasks;
const nextCursor = hasMore ? items[items.length - 1]?.id : undefined;
return { items, nextCursor } as const;
}
Count tasks per status (groupBy)
export async function getTaskStatusCounts(userId: string) {
const grouped = await prisma.task.groupBy({
by: ["status"],
where: { assigneeId: userId },
_count: { _all: true },
});
return grouped.map(g => ({ status: g.status, count: g._count._all }));
}
Filter by Project (or Organization) and date window
interface GetUserProjectTasksParams {
userId: string;
projectId?: string;
organizationId?: string;
from?: Date;
to?: Date;
}
export async function getUserProjectTasks(params: GetUserProjectTasksParams) {
const { userId, projectId, organizationId, from, to } = params;
return prisma.task.findMany({
where: {
assigneeId: userId,
...(from || to ? { createdAt: { gte: from, lte: to } } : {}),
...(projectId ? { ticket: { projectId } } : {}),
...(organizationId ? { ticket: { organizationId } } : {}),
},
include: { ticket: { select: { id: true, title: true, projectId: true } } },
orderBy: { createdAt: "desc" },
});
}
Create a Task for a Ticket and assign it to a User
interface CreateTaskParams {
ticketId: string;
title: string;
assigneeId?: string;
}
export async function createTask(params: CreateTaskParams) {
const { ticketId, title, assigneeId } = params;
return prisma.task.create({
data: {
ticketId,
title,
...(assigneeId ? { assignee: { connect: { id: assigneeId } } } : {}),
},
include: { ticket: true, assignee: true },
});
}
Reassign a Task to another User
export async function reassignTask(taskId: string, newAssigneeId: string) {
return prisma.task.update({
where: { id: taskId },
data: { assigneeId: newAssigneeId },
select: { id: true, assigneeId: true },
});
}
Tasks with Workflow Runs (latest first)
export async function getTasksWithRuns(userId: string) {
return prisma.task.findMany({
where: { assigneeId: userId },
include: {
runs: {
orderBy: { updatedAt: "desc" },
select: { id: true, status: true, currentStep: true, updatedAt: true },
},
ticket: { select: { id: true, title: true } },
},
orderBy: [{ sortIndex: "asc" }, { createdAt: "desc" }],
});
}
Load User with a trimmed tasksAssigned
slice for dashboards
export async function getUserWithPreviewTasks(userId: string) {
return prisma.user.findUnique({
where: { id: userId },
select: {
id: true,
name: true,
tasksAssigned: {
take: 5,
orderBy: [{ sortIndex: "asc" }, { createdAt: "desc" }],
include: { ticket: { select: { id: true, title: true, status: true } } },
},
},
});
}
Example: Minimal API route using validateUserSession()
// File: src/app/api/user/tasks/route.ts
import { NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import { validateUserSession } from "@/lib/permissions";
export async function GET() {
const session = await validateUserSession();
if (!session?.user?.id) {
return NextResponse.json({ error: { code: "UNAUTHORIZED" } }, { status: 401 });
}
const tasks = await prisma.task.findMany({
where: { assigneeId: session.user.id },
include: { ticket: { select: { id: true, title: true, status: true } } },
orderBy: [{ sortIndex: "asc" }, { createdAt: "desc" }],
take: 50,
});
return NextResponse.json({ data: tasks });
}
Tips
- Select only the fields you need; avoid
include: true
for large nested shapes. - For lists, use stable ordering (
sortIndex
, thencreatedAt
) to prevent cursor drift. - Prefer cursor-based pagination for long lists; include an index on the order columns.
- Use
groupBy
for aggregated counts and pair with a separate list fetch for items. - For AI use, provide concise shapes (ids, titles, statuses) to reduce token/JSON size.