Course

Server Actions - Delete

So far, we've learned how to create and read data from our database. In this lesson, we'll learn how to delete data from our database.

Creating a New Server Action - Delete a Product

Let's start by creating a new server action that will delete a product from our database.

Let's open our file and add the following code:

products.ts;

export async function deleteProduct() {
  try {
    // todo: delete the product
  } catch (error) {
    console.error("Error deleting product", error);
  }
}

So far, this just follows the pattern of our other server actions. We have an async function that we wrap the logic of in a try/catch block.

Can you think of how we might need in our arguments to delete a product?

Hint
monkey

We need to know which product to delete. We can do this by passing the product's ID to the server action.

We use the ID because it's a unique identifier for each product.

Meaning we can use it to find only the product we want to delete.

If we tried to delete a product by name, we might accidentally delete multiple products with the same name!

Let's add the product ID to our server action:

products.ts;

// add our ID argument
export async function deleteProduct(productId: string) {
  // make sure we connect to the database
  await dbConnect();
  try {
    // delete the product here
  } catch (error) {
    console.error("Error deleting product", error);
  }
}

Before we can delete the product, let's decide what we need our function to return.

In previous lessons, we've returned the product we created or read from the database. We would often return the of the newly created or updated product. Why was this? Because we needed to know the ID of the product to reroute to the product page.

For this delete action, we don't need to return the product. We just need to know if the product was successfully deleted.

Let's update our server action to return a boolean value:

products.ts;

export async function deleteProduct(productId: string): Promise<boolean> {
  // make sure we connect to the database
  await dbConnect();
  try {
    // delete the product here
    return true;
  } catch (error) {
    console.error("Error deleting product", error);
    return false;
  }
}

Now we've gotten the boilerplate set up for our delete action. Let's write the code to delete the product.

Deleting a Product

To delete a product, we need to use the method from Mongoose.

The method deletes the first document that matches the query. We write a query for the same way we do for or , we pass it in as an object.

Can you use the method and the product ID to delete the product?

Hint
monkey
products.ts;

export async function deleteProduct(productId: string): Promise<boolean> {
  // make sure we connect to the database
  await dbConnect();
  try {
    // delete the product by ID
    await Product.deleteOne({ _id: productId });
    return true;
  } catch (error) {
    console.error("Error deleting product", error);
    return false;
  }
}

This works to a degree. If we pass in an ID that doesn't exist, Mongoose will not throw an error. It will just return a success message.

This is because Mongoose doesn't know if the document exists or not. It just tries to delete the document that matches the query.

If the document doesn't exist, Mongoose will return a success message because it didn't find anything to delete.

This is a bit of a problem. We want to know if the product was successfully deleted or not.

To do this, we can use the property of the result of the method.

The property tells us how many documents were deleted. If the is 0, then no documents were deleted.

Let's update our server action to return a boolean value based on the :

products.ts;

export async function deleteProduct(productId: string): Promise<boolean> {
  // make sure we connect to the database
  await dbConnect();
  try {
    // delete the product by ID
    const result = await Product.deleteOne({ _id: productId });
    return result.deletedCount === 1;
  } catch (error) {
    console.error("Error deleting product", error);
    return false;
  }
}

Now our server action will return if the product was successfully deleted and if it wasn't.

Implementing the Delete Action

Now that we've created the server action, let's integrate it into our application.

We already have a component that we can use to delete a product. We'll import the server action and call it when the user clicks the button.

Let's open up .

You'll see it's already importing the as a prop, which is all we'll need to make this work.

Let's import our server action and call it when the user clicks the button.

DeleteProduct.tsx

"use client";

// import useRouter so we can redirect the user after deleting the product
import { useRouter } from "next/navigation";
import { TrashIcon } from "lucide-react";

// import the deleteProduct server action
import { deleteProduct } from "@/lib/actions/products";
import { Button } from "@/components/ui/button";
export default function DeleteProduct({ id }: { id: string }) {
  // initialize the router
  const router = useRouter();

  // create a function to handle the delete operation
  const handleDelete = async () => {
    const didDelete = await deleteProduct(id);
    if (didDelete) router.push("/search");
    // else show error, like a toast
  };

  return (
    //...
        <div className="flex justify-center gap-4">
          {/* add the onClick event */}
          <Button onClick={handleDelete} variant="destructive">
            Confirm Delete
          </Button>
          <Button variant="outline">Cancel</Button>
        </div>
    //...
  );

}

There's also cancel button that doesn't do anything yet. You can add a event to it and redirect the user back to the product page.

//
<Button onClick={() => router.push(`/product/view/${id}`)} variant="outline">Cancel</Button>

Conclusion

In this lesson, we learned how to delete data from our database. We created a new server action that deletes a product from our database.

We used the method from Mongoose to delete the product.

We also updated our component to call the server action when the user clicks the button.

0 Comments

"Please login to view comments"

glass-bbok

Join the Conversation!

Subscribing gives you access to the comments so you can share your ideas, ask questions, and connect with others.

Upgrade your account
tick-guideNext Lesson

Caching our Server Actions