How to link one existing entry to another programmatically?

Hey all,

I have a case where I need to link from one entry’s reference field to another entry (JavaScript).

const localeEntry = await env.getEntry(filterLocaleEntries[‘fr-FR’]); //<= gets the correct entry
contentEntry.fields[‘filterLocale’] = localeEntry; //assigns the field
await contentEntry.update(); //fails

Is this even the correct approach. Tried many angles, but no luck so far, any help is appreciated.

Hey @aldub,

I’m a bit confused as to what exactly is your referencing field - could you clarify what would that be?

I’m talking about the field ‘filterLocale’ that needs to point to another entry. But how? We cannot assign the id, because it’s a system property (sys.id), and it doesn’t seem like we can assign the entry object either.

I’m also trying to do something similar. I want to change entry link field to point to different entry. I’ve dug through the documentation of both the contentful cli and content management SDK. I’ve found the deriveLinkedEntries function to build a new entry based on content in the Entry but I have yet to find a way to simply change a link field to point to a different, existing entry.

@aldub @kyle.r

This gets you a complete entry.
Entries are linked to each other not by full entities, but Link objects. They look like the following:

{
  "sys": {
    "type": "Link",
    "linkType": "Entry ",
    "id": "<use sys.id of the linked entity, e.g. localeEntry.sys.id>"
  }
}

Assign these to your link field (mind that you need to specify the locale you want to assign the link to, so it would probably look more something like this:

contentEntry.fields.filterLocale['fr-FR'] = linkObject

Does this work?

Best,
Stephan

1 Like

Thanks Stephan, that’s what I was trying to do but I was getting an error due to using the local “en-Us” instead of “en-US”. The code sample for update entry us using “en-Us” and set me down the wrong path. Corrected the local and my entries updated.

https://www.contentful.com/developers/docs/references/content-management-api/#/reference/entries/entry/create-update-an-entry/console/js

// Update entry
client.getSpace('<space_id>')
.then((space) => space.getEntry('<entry_id>'))
.then((entry) => {
  entry.fields.title['en-Us'] = 'New entry title'
  return entry.update()
})
.then((entry) => console.log(`Entry ${entry.sys.id} updated.`))
.catch(console.error)

Ouch, thanks for pointing this out - we’ll correct that in our docs!

Edit: done :white_check_mark:

1 Like

Hi all, i tried this solution and … while technically it worked, it was quite cumbersome.

           const linkString = `{
                "${CONTENTFUL_DEFAULT_LOCALE}": {
                    "sys": {
                        "type": "Link",
                        "linkType": "Entry",
                        "id": "${localeEntryId}"
                    }
                }
              }`;
            const linkObject = JSON.parse(linkString);                
            contentEntry.fields['filterLocale'] = linkObject;
            contentEntry.update();

Are there any plans to create a corresponding API point that would eliminate the need for constructing the sys object “by hand”? This should really be a one-liner with 2 parameters. If not, is there a place in the docs that breaks down this very common operation and makes it crystal clear? The current approach is far from obvious.

@stephan.schneider, @gabriel would be good to get a reply on this.

Hej, I apparently didn’t get a notification on this, first time seeing your reply after this has been solved.

Why so complicated?

const link = {
  sys: {
    type: 'Link',
    linkType: 'Entry',
    id: localeEntryId
  }
}

const localeLink = {
  [CONTENTFUL_DEFAULT_LOCALE]: link
}

contentEntry.fields['filterLocale'] = localeLink

Of course you can put both objects into one if it makes sense (e.g. always just one locale):

contentEntry.fields['filterLocale'] = {
  [CONTENTFUL_DEFAULT_LOCALE]: {
    sys: {
      type: 'Link',
      linkType: 'Entry',
      id: localeEntryId
    }
  }
}

Can’t speak for the SDK and their abstractions, but this is how it’s expected on the API level, further abstractions are easy to implement, though:

function linkEntry (id, locale = CONTENTFUL_DEFAULT_LOCALE) {
  return {
    [locale]: {
      sys: {
        type: 'Link',
        linkType: 'Entry',
        id
      }
    }
  }
}

contentEntry.fields['filterLocale'] = linkEntry(localeEntryId)
1 Like

I understand my code could have been simpler, but my point still stands. You’re expecting users of your API to construct a system object with specific fields. This is an issue all over the place is the Management API, where without proper docs or a reply like this one, it could take hours (or days) to figure out.

3 Likes

Hi,

I’m trying hard to do this entry linking in .Net
Is there an example of how to do this somewhere?

var childEntry = new Entry<dynamic>
{
    SystemProperties = new SystemProperties
    {
        Locale = DefaultLocale
    },
    Fields = new
    {
        Name = WrapInLocale("I'm the baby"),
    }
};

// leaving out the code where I create the child entry using the CMA client

var parentEntry = new Entry<dynamic>
{
    SystemProperties = new SystemProperties
    {
        Locale = DefaultLocale
    },
    Fields = new
    {
        Name = WrapInLocale("I'm the parent"),
        MyLinkedChildEntry = WrapInLocale(new Entry<dynamic>
        {
            SystemProperties =
            {
                Type = "Link",
                LinkType = "Entry",
                Id = childEntry.SystemProperties.Id
            }
        })
    }
};
1 Like

Hi how can i do this in java…

Please check my migration script.

module.exports = function (migration) {

migration.transformEntriesToType({
    sourceContentType: 'brandComponent',
    targetContentType: 'genericBrandComponent',
    from: ['internalName','brandName', 'slug', 'description','seo','media'],
    shouldPublish: true,
    updateReferences: true,
    removeOldEntries: false,
    identityKey: function (fields) {
      //const value = ;
      return fields.slug['en-US'].toString();
    },
    transformEntryForLocale: function (fromFields, currentLocale) {
      return {
        internalName: `${fromFields.internalName[currentLocale]}`,
        name: `${fromFields.brandName[currentLocale]}`,
        slug: `${fromFields.slug[currentLocale]}`,
        description: `${fromFields.description[currentLocale]}`,
        seo: fromFields.seo[currentLocale],
        //richText:fromFields.richText[currentLocale],
        media:fromFields.media[currentLocale],
        website:{
            "sys": {
              "type": "Link",
              "linkType": "Entry ",
              "id": "5D4h7N2rXhb9xu0nF81bYk"
            }
          }
        
      };
    }
  });

};

I need to link existing website component to Website Attribute ??