How to find IDs for consistent models / fields across environments?

I have a multi-environment instance of Dato where I’m attempting to write migrations to update the content models (per the docs here).

Here’s my migration script:

  // DatoCMS migration script

  // For more examples, head to our Content Management API docs:
  // https://www.datocms.com/docs/content-management-api

  //whatwedo model
  const itemTypeId = '{id}';

  //delete unused fields
  const workDetailBlocksId = '{id}';
  await client.fields.destroy(workDetailBlocksId);
  console.log('deleted work detail blocks');

  const servicesFieldId = '{id}';
  await client.fields.destroy(servicesFieldId);
  console.log('deleted service blocks');

  //add field for value prop module
  const field = await client.fields.create(itemTypeId, {
    label: 'Services',
    fieldType: 'block',
    apiKey: 'services',
    hint: '3-up component to display services',
    localized: true,
    validators: {
      richTextBlocks: {
        itemTypes: '{id}',
      },
    }
  });
  console.log(field);
}

Running the basic migration script dato migrate --destination=test1, the environment is created, but when the script is run, I get the following error:

Running 1598545728_whatwedo.js...(node:4576) UnhandledPromiseRejectionWarning: ApiException: 404 NOT_FOUND (details: {"message":"Couldn't find Field with 'id'={id} [WHERE \"item_types\".\"environment_id\" = $1]"})
...

The id values I put into the script are based off of the models in the Primary Environment. I find that if I sub in the new id values and run the migration on the new environment it seems to work reliably.

Is this expected behavior? If it is, I guess in order to apply these to production I’d have to edit the migration script to reflect production IDs?

Hi @operations

when you fork an environment, IDs in the forked environment are different from the ones in the primary environment. This is why you got that error using your primary environment IDs in your migration script.

In fact

$ dato migrate --destination=test1

will create a fork from the primary environment as first step and it will run pending migrations against it.

There is a missing part in our documentation though (we are working on it!). In some circumstances you can use models and field api_keys instead of IDs ( https://www.datocms.com/product-updates/april-2020-update, read the “Reference models by API keys” section ).

So this means that you can call functions like these with either an ID or an api_key :

client.itemTypes.find('123') // find model with ID 123 in the given environment
client.itemTypes.find('my-model') // find model with `api_key` 'my-model' in the given environment

client.fields.destroy('678') // destroy field with ID 678 in the given environment
client.fields.destroy('my-model::my-field') // destroy field with `api_key` 'my-field' inside model with `api_key` 'my-model' (notice the `::` used to separate model's `api_key` from field's `api_key`)

But when you have to reference a model or a field in the payload, then you have to use the IDs:

const field = await client.fields.create('my-model', {
    label: 'Services',
    fieldType: 'block',
    apiKey: 'services',
    hint: '3-up component to display services',
    localized: true,
    validators: {
      richTextBlocks: {
        itemTypes: ['5389234'], // here you must use IDs, not `api_key`s
      },
    }
  });

In this case, you can do it in two steps like this:

const blockModel = client.itemTypes.find('my-block-model');
const field = await client.fields.create('my-model', {
    label: 'Services',
    fieldType: 'block',
    apiKey: 'services',
    hint: '3-up component to display services',
    localized: true,
    validators: {
      richTextBlocks: {
        itemTypes: [blockModel.id], // here you must use IDs, not `api_key`s
      },
    }
  });

Given this information, I think that you can update your migration code and it should work :slight_smile:

Let me know if you need further assistance!

1 Like

Super helpful – I was wondering if there was a way to grab the IDs based on the API key and this does what I was looking for. This is great, thank you!

1 Like