How do i work with a potentially nullable field in prisma ORM and MongoDB that references the id of another model?

14 views Asked by At
model Product{
  id String @id @default(auto()) @map("_id") @db.ObjectId
  name String
  subcategoryId String @db.ObjectId
  subcategory Subcategory? @relation(fields: [subcategoryId],references: [id])
  categoryId String @db.ObjectId
  category Category @relation(fields: [categoryId],references: [id])
  price Float
  brand String
  isFeatured Boolean @default(false)
  isArchived Boolean @default(false)
  sizeId String[] @db.ObjectId
  size Size[] @relation(fields: [sizeId], references: [id])
  reviews Review[]
  images ProductImage[]
  orderItem OrderItem[]
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt


  @@index([categoryId])
  @@index([sizeId])
   
}

model Subcategory{
  id String @id @default(auto()) @map("_id") @db.ObjectId
  billboardId String @db.ObjectId
  billboard BillBoard @relation(fields: [billboardId],references: [id])
  categoryId String @db.ObjectId
  category Category @relation(fields: [categoryId],references: [id])
  product Product[]
  name String
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

}

export const ProductSchema = z.object({
  name: z.string().min(1),
  categoryId: z.string().min(1),
  subcategoryId: z.string().optional(),
  sizeId: z.array(z.string()),
  price: z.coerce.number().min(1),
  brand: z.string().min(1),
  isFeatured: z.boolean().default(false).optional(),
  isArchived: z.boolean().default(false).optional(),
  images: z.array(ProductImageSchema),
});

import { currentRole } from "@/hooks/use-current-role-server";
import { currentUser } from "@/hooks/use-current-user-server";
import { db } from "@/lib/db";
import { UserRole } from "@prisma/client";
import { NextResponse } from "next/server";

export async function POST(req: Request) {
  try {
    const user = await currentUser();
    const role = await currentRole();
    const userId = user?.id;
    const body = await req.json();
    const {
      name,
      categoryId,
      subcategoryId,
      sizeId,
      price,
      brand,
      isArchived,
      isFeatured,
      images,
    } = body;

    if (!userId) {
      return new NextResponse("Unauthorized", { status: 401 });
    }
    if (role !== UserRole.ADMIN) {
      return new NextResponse("Unauthorized", { status: 401 });
    }
    if (!name) {
      return new NextResponse("Name is required", { status: 400 });
    }
    if (!categoryId) {
      return new NextResponse("Category is required", { status: 400 });
    }

    if (!sizeId || sizeId.length === 0) {
      return new NextResponse("Size is required", { status: 400 });
    }

    if (!price) {
      return new NextResponse("Size is required", { status: 400 });
    }

    const product = await db.product.create({
      data: {
        name,
        categoryId,
        subcategoryId: subcategoryId || null,
        sizeId,
        price,
        brand,
        isArchived,
        isFeatured,
        images,
      },
    });

    return NextResponse.json(product);
  } catch (error) {
    console.log("[PRODUCT_POST]", error);
    return new NextResponse("Internal Error", { status: 500 });
  }
}


If you look at my Prisma schema you will notice that i want the subcategories to be optional hence the ? after it. If you look a the Zod schema too you will notice i also have z.string.optional() but when i try to submit the form i get strange errors when the subcategoryId is not selected but it works when it is so i know the issue is from subcategory not being selected i need a solution because i want subcategories to be optional

The error i normally get

Invalid `prisma.product.create()` invocation:

{
  data: {
    name: "Sneakers",
    categoryId: "6604bc28973d8ff95e7b4d44",
    subcategoryId: null,
    sizeId: [
      "6600a1124992965a353051c2",
      "6604b694973d8ff95e7b4d3a"
    ],
    price: 30300,
    brand: "Brand",
    isArchived: false,
    isFeatured: true,
    images: [
      {
        colorId: "65f9a296f87aafb1836df2d5",
        imageURLs: [
          "https://res.cloudinary.com/dezuiqfsq/image/upload/v1711638173/ckrn1qi0bsdtfu8kn0zf.jpg"
        ]
      }
    ],
+   category: {
+     create: CategoryCreateWithoutProductInput | CategoryUncheckedCreateWithoutProductInput,
+     connectOrCreate: CategoryCreateOrConnectWithoutProductInput,
+     connect: CategoryWhereUniqueInput
+   }
  }
}

Argument `category` is missing.
    at Cn (C:\Users\brian\Documents\Portfolio\cms\node_modules\@prisma\client\runtime\library.js:116:5888)
    at _n.handleRequestError (C:\Users\brian\Documents\Portfolio\cms\node_modules\@prisma\client\runtime\library.js:123:6510)
    at _n.handleAndLogRequestError 
..................
}

1

There are 1 answers

0
Shea Hunter Belsky On

You're correct that subcategory on the Product model is nullable, but subcategoryId (the field right above it) is not. As far as Prisma is concerned, you need to specify the subcategoryId field to create a new Product. Just make subcategoryId nullable and you should be good to go!

subcategoryId String? @db.ObjectId