Documentation Index
Fetch the complete documentation index at: https://docs.twenty.com/llms.txt
Use this file to discover all available pages before exploring further.
Relations connect two objects together. In Twenty, relations are always bidirectional — every relation has two sides, and each side is declared as a field that references the other.
| Tip relație | Descriere | Are cheie străină? |
|---|
MANY_TO_ONE | Multe înregistrări ale acestui obiect indică către o singură înregistrare a țintei | Da (joinColumnName) |
ONE_TO_MANY | O înregistrare a acestui obiect are multe înregistrări ale țintei | No (the inverse side) |
Cum funcționează relațiile
Fiecare relație necesită două câmpuri care se referențiază reciproc:
- Partea MANY_TO_ONE — se află pe obiectul care deține cheia străină.
- Partea ONE_TO_MANY — se află pe obiectul care deține colecția.
Ambele câmpuri folosesc FieldType.RELATION și se referențiază încrucișat prin relationTargetFieldMetadataUniversalIdentifier.
Exemplu: Post Card are mulți destinatari
A PostCard can be sent to many PostCardRecipient records. Fiecare destinatar aparține exact unui Post Card.
Pasul 1: Definiți partea ONE_TO_MANY pe PostCard (partea “one”):
src/fields/post-card-recipients-on-post-card.field.ts
import { defineField, FieldType, RelationType } from 'twenty-sdk/define';
import { POST_CARD_UNIVERSAL_IDENTIFIER } from '../objects/post-card.object';
import { POST_CARD_RECIPIENT_UNIVERSAL_IDENTIFIER } from '../objects/post-card-recipient.object';
// Export so the other side can reference it
export const POST_CARD_RECIPIENTS_FIELD_ID = 'a1111111-1111-1111-1111-111111111111';
// Import from the other side
import { POST_CARD_FIELD_ID } from './post-card-on-post-card-recipient.field';
export default defineField({
universalIdentifier: POST_CARD_RECIPIENTS_FIELD_ID,
objectUniversalIdentifier: POST_CARD_UNIVERSAL_IDENTIFIER,
type: FieldType.RELATION,
name: 'postCardRecipients',
label: 'Post Card Recipients',
icon: 'IconUsers',
relationTargetObjectMetadataUniversalIdentifier: POST_CARD_RECIPIENT_UNIVERSAL_IDENTIFIER,
relationTargetFieldMetadataUniversalIdentifier: POST_CARD_FIELD_ID,
universalSettings: {
relationType: RelationType.ONE_TO_MANY,
},
});
Pasul 2: Definiți partea MANY_TO_ONE pe PostCardRecipient (partea “many” — deține cheia străină):
src/fields/post-card-on-post-card-recipient.field.ts
import { defineField, FieldType, RelationType, OnDeleteAction } from 'twenty-sdk/define';
import { POST_CARD_UNIVERSAL_IDENTIFIER } from '../objects/post-card.object';
import { POST_CARD_RECIPIENT_UNIVERSAL_IDENTIFIER } from '../objects/post-card-recipient.object';
// Export so the other side can reference it
export const POST_CARD_FIELD_ID = 'b2222222-2222-2222-2222-222222222222';
// Import from the other side
import { POST_CARD_RECIPIENTS_FIELD_ID } from './post-card-recipients-on-post-card.field';
export default defineField({
universalIdentifier: POST_CARD_FIELD_ID,
objectUniversalIdentifier: POST_CARD_RECIPIENT_UNIVERSAL_IDENTIFIER,
type: FieldType.RELATION,
name: 'postCard',
label: 'Post Card',
icon: 'IconMail',
relationTargetObjectMetadataUniversalIdentifier: POST_CARD_UNIVERSAL_IDENTIFIER,
relationTargetFieldMetadataUniversalIdentifier: POST_CARD_RECIPIENTS_FIELD_ID,
universalSettings: {
relationType: RelationType.MANY_TO_ONE,
onDelete: OnDeleteAction.CASCADE,
joinColumnName: 'postCardId',
},
});
Circular imports: both relation fields reference each other’s universalIdentifier. To avoid circular import issues, export your field IDs as named constants from each file and import them in the other. Sistemul de build le rezolvă în timpul compilării.
Relaționarea cu obiectele standard
Pentru a crea o relație cu un obiect Twenty încorporat (Person, Company etc.), utilizați STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS:
src/fields/person-on-self-hosting-user.field.ts
import {
defineField,
FieldType,
RelationType,
OnDeleteAction,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { SELF_HOSTING_USER_UNIVERSAL_IDENTIFIER } from '../objects/self-hosting-user.object';
export const PERSON_FIELD_ID = 'c3333333-3333-3333-3333-333333333333';
export const SELF_HOSTING_USER_REVERSE_FIELD_ID = 'd4444444-4444-4444-4444-444444444444';
export default defineField({
universalIdentifier: PERSON_FIELD_ID,
objectUniversalIdentifier: SELF_HOSTING_USER_UNIVERSAL_IDENTIFIER,
type: FieldType.RELATION,
name: 'person',
label: 'Person',
description: 'Person matching with the self hosting user',
isNullable: true,
relationTargetObjectMetadataUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
relationTargetFieldMetadataUniversalIdentifier: SELF_HOSTING_USER_REVERSE_FIELD_ID,
universalSettings: {
relationType: RelationType.MANY_TO_ONE,
onDelete: OnDeleteAction.SET_NULL,
joinColumnName: 'personId',
},
});
Proprietăți ale câmpului de relație
| Proprietate | Obligatoriu | Descriere |
|---|
tip | Da | Trebuie să fie FieldType.RELATION |
relationTargetObjectMetadataUniversalIdentifier | Da | universalIdentifier al obiectului țintă |
relationTargetFieldMetadataUniversalIdentifier | Da | universalIdentifier al câmpului corespunzător de pe obiectul țintă |
universalSettings.relationType | Da | RelationType.MANY_TO_ONE sau RelationType.ONE_TO_MANY |
universalSettings.onDelete | Doar MANY_TO_ONE | Ce se întâmplă atunci când înregistrarea referențiată este ștearsă: CASCADE, SET_NULL, RESTRICT sau NO_ACTION |
universalSettings.joinColumnName | Doar MANY_TO_ONE | Numele coloanei din baza de date pentru cheia străină (de ex., postCardId) |
Inline relation fields
You can also declare a relation directly inside defineObject. When inline, omit objectUniversalIdentifier — it’s inherited from the parent object:
export default defineObject({
universalIdentifier: '...',
nameSingular: 'postCardRecipient',
// ...
fields: [
{
universalIdentifier: POST_CARD_FIELD_ID,
type: FieldType.RELATION,
name: 'postCard',
label: 'Post Card',
relationTargetObjectMetadataUniversalIdentifier: POST_CARD_UNIVERSAL_IDENTIFIER,
relationTargetFieldMetadataUniversalIdentifier: POST_CARD_RECIPIENTS_FIELD_ID,
universalSettings: {
relationType: RelationType.MANY_TO_ONE,
onDelete: OnDeleteAction.CASCADE,
joinColumnName: 'postCardId',
},
},
// … other fields
],
});