Datamodel & Migrations

Migrations (MongoDB)

Overview

MongoDB is a schemaless database, which means it is possible to insert data of various structures into it. MongoDB never complains because a piece of inserted data doesn't adhere to some predefined, expected format. This is different from relational databases where data that's inserted needs to adhere to the predefined database schema.

This changes when using MongoDB with Prisma. Prisma adds a "schema" (i.e. the Prisma datamodel) on top of MongoDB. That's why migrations now become a relevant topic when using MongoDB with Prisma.

The general process for performing a migration with Prisma is as follows:

  1. Adjust the datamodel file to reflect the new desired schema
  2. Run prisma1 deploy to apply the changes and perform the migration of the Prisma API (and potentially) the underlying MongoDB database)

When going through that process, Prisma will only ever make additive structural changes to the underlying MongoDB database(s).

During a migration, Prisma will never:

  • Delete an existing collection
  • Rename an existing collection
  • Drop an existing database
  • Delete or change any field names on existing documents

Be aware that this might lead to dangling collections or fields, i.e. collections or fields that still exist in the underlying MongoDB database but that can't be accessed through the Prisma API.

During a migration, Prisma might:

  • Create new collections
  • Create new documents
  • Create new fields on existing documents

Examples

Renaming a collection

Scenario 1: With the @db directive

Assume you have the following datamodel:

type User @db(name: "users") {
  id: ID! @id
  name: String!
}

Because the @db directive is used on the type, the name of the type in the Prisma API is decoupled from the name of the collection in the underlying MongoDB.

To rename the type in the Prisma API, you need to adjust the name of the type in your Prisma datamodel:

type Person @db(name: "users") {
  id: ID! @id
  name: String!
}

To apply the changes and update the Prisma API, run prisma1 deploy.

Scenario 2: Without the @db directive

Assume you have the following datamodel:

type User {
  id: ID! @id
  name: String!
}

Because there is no @db directive, the collection in the underlying MongoDB is also called User.

To rename the type in the Prisma API, you need to adjust the name of the type in your Prisma datamodel:

type Person {
  id: ID! @id
  name: String!
}

When running prisma1 deploy, there are three things done by Prisma:

  • Remove CRUD operations for the User type from the Prisma API
  • Expose CRUD operations for the new Person type in the Prisma API
  • Create a new Person collection in the underlying database

The underlying User collection remains untouched, it stays there as a dangling collection.

If you want to still use the data in the dangling User collection for the new Person type in your Prisma API, you need to manually rename the collection in your MongoDB (and likely delete the empty Person collection that was ).

Renaming a field of a collection

Assume you have the following datamodel:

type User {
  id: ID! @id
  name: String!
}

Now you want to rename the name field to lastName. This can actually mean three things:

  1. You want to rename the field only in the Prisma API
  2. You want to rename the field only in the underlying MongoDB
  3. You want to rename the field in both, the Prisma API and the underlying MongoDB

Scenario 1: Renaming only in the Prisma API

If you want to rename the field only in the Prisma API, you can do so by changing the name of the field in the datamodel and addding the @db directive to create a mapping from the lastName datamodel field to the name field in the underlying MongoDB:

type User {
  id: ID! @id
  lastName: String! @db(name: "name")
}

Now run prisma1 deploy to apply the changes.

Scenario 2: Renaming only in the underlying MongoDB

Because Prisma never performs any structural changes to your underlying MongoDB, the only way to achieve this is by renaming the field manually.

After you've done this, your Prisma API of course has not changed. This also means that when you're now trying to retrieve the name of a document in the User collection via the Prisma API, Prisma will throw an error because the name does not exist any more in the underlying MongoDB.

To prevent this, you have two options:

  • Delete the name field from the datamodel and run prisma1 deploy. This means there is no way to get access to the new lastName through Prisma.
  • Also rename the field in the Prisma API, see the third scenario for more info on this.

Scenario 3: Renaming in the Prisma API and the underlying MongoDB

Similar to the second scenario, you first need to manually rename the field in the underlying MonngoDB.

Once this is done, you can rename the field in the Prisma API. Adjust the datamodel to look as follows:

type User {
  id: ID! @id
  lastName: String!

Finally, run prisma1 deploy.

Note that the Prisma CLI might require you to run prisma1 deploy --force to execute this operation. This is a bug in the CLI that has been reported here.

Deleting a collection

Assume you have the following datamodel:

type User {
  id: ID! @id
  name: String!
}

type Post {
  id: ID!
  title: String!
}

Now you want to remove the Post type from the Prisma API and drop the Post collection in the underlying MongoDB.

You first need to remove the Post from the datamodel:

type User {
  id: ID! @id
  name: String!
}

Now run prisma1 deploy to apply the changes. This does not change anything in the underlying MongoDB, the Post collections remains there as a dangling collection.

To get rid of the dangling collection, you need to manually remove the collection from your MongoDB database.