- Comprender el concepto de objetos embebidos (embedded objects)
- Aprender a usar
@Column(() => Class)para mapear objetos complejos - Implementar transformers para tipos de datos complejos (arrays, JSON)
- Dominar diferentes patrones de mapeo de datos en una sola tabla
- Aplicar métodos de negocio en objetos embebidos
Los objetos embebidos permiten mapear objetos complejos a columnas de una tabla sin crear relaciones entre tablas. Se "aplanan" en la estructura de la tabla principal.
| Tipo | Descripción | Ejemplo |
|---|---|---|
| Múltiples Columnas | Un objeto se mapea a varias columnas | Address → street, city, zipCode, country |
| Separado por Comas | Array se almacena como string | ["tag1", "tag2"] → "tag1,tag2" |
| JSON | Objeto complejo como JSON | {theme: "dark"} → '{"theme":"dark"}' |
✅ Ventajas:
- Sin JOINs necesarios
- Consultas más rápidas
- Datos cohesivos
- Fácil de entender
❌ Desventajas:
- No reutilizable entre entidades
- Duplicación de columnas
- Queries complejas para filtrar
npm run embeddedEscenario: Empresa con dirección principal y de facturación
- Mapeo de
Addressa múltiples columnas con prefijos - Comparación de direcciones
- Validación de información
Escenario: Empleado con contacto, trabajo y skills
- Múltiples objetos embebidos en una entidad
- Transformers para arrays y JSON
- Métodos de negocio en objetos embebidos
Escenario: Filtrar por propiedades de objetos embebidos
- Consultas SQL directas a campos embebidos
- QueryBuilder con campos "aplanados"
Escenario: Modificar objetos embebidos en tiempo de ejecución
- Agregar/quitar elementos de arrays
- Actualizar configuraciones JSON
- Persistir cambios
erDiagram
Company ||--o{ Address : embeds
Company ||--o{ Settings : embeds
Employee ||--o{ Address : embeds
Employee ||--o{ ContactInfo : embeds
Employee ||--o{ WorkInfo : embeds
Company {
int id PK
string name
string email
string phone
string website
string main_address_street
string main_address_city
string main_address_zipCode
string main_address_country
string billing_address_street
string billing_address_city
string billing_address_zipCode
string billing_address_country
text tags
text settings
boolean isActive
datetime createdAt
datetime updatedAt
}
Employee {
int id PK
string firstName
string lastName
string documentNumber
string home_street
string home_city
string home_zipCode
string home_country
string contact_email
string contact_phone
string contact_emergencyContact
string contact_emergencyPhone
string work_department
string work_position
decimal work_salary
date work_hireDate
string work_manager
text skills
text performance
boolean isActive
datetime createdAt
datetime updatedAt
}
export class Address {
@Column()
street!: string;
@Column()
city!: string;
// Métodos de negocio
getFullAddress(): string {
return `${this.street}, ${this.city}`;
}
}
@Entity()
export class Company {
@Column(() => Address, { prefix: "main_address_" })
mainAddress!: Address;
}@Column({
type: "text",
transformer: {
to: (value: string[]) => value ? value.join(',') : '',
from: (value: string) => value ? value.split(',') : []
}
})
tags!: string[];@Column({
type: "text",
transformer: {
to: (value: any) => JSON.stringify(value),
from: (value: string) => JSON.parse(value || '{}')
}
})
settings!: {
theme: string;
notifications: boolean;
};// QueryBuilder con campos "aplanados"
const companies = await repository
.createQueryBuilder("company")
.where("company.main_address_city = :city", { city: "Buenos Aires" })
.getMany();-
Información de dirección
- Direcciones postales
- Ubicaciones geográficas
- Datos que siempre van juntos
-
Configuraciones simples
- Preferencias de usuario
- Settings de aplicación
- Metadatos pequeños
-
Datos cohesivos
- Información de contacto
- Detalles de producto
- Datos que no necesitan ser reutilizados
-
Arrays simples
- Tags o etiquetas
- Listas de categorías
- Skills o habilidades
-
Datos que necesitan relaciones
- Referencias a otras entidades
- Datos que requieren integridad referencial
-
Información reutilizable
- Entidades que se usan en múltiples lugares
- Datos que requieren normalización
-
Consultas complejas
- Datos que requieren filtros avanzados
- Información que necesita índices específicos
-
Datos grandes
- Objetos JSON muy grandes
- Arrays con muchos elementos
Al ejecutar el ejemplo verás:
✅ Empresa creada: TechCorp SA
📍 Ubicación principal: Buenos Aires, Argentina
📄 Facturación: Córdoba, Argentina
🏷️ Tags: technology, software, innovation
🔄 Misma dirección: No
✅ Empleado creado: María González - Senior Developer en Engineering
📍 Ubicación: Buenos Aires, Argentina
🆘 Emergencia: Configurado
💼 Experiencia: 4 años (Senior)
🎯 Skills: JavaScript, TypeScript, React, Node.js, PostgreSQL
⭐ Rating: 4.5/5
🏢 Empresas en Buenos Aires: 2
• TechCorp SA - Buenos Aires, Argentina
• StartupHub - Buenos Aires, Argentina
👨💻 Empleados de Engineering: 2
• María González - Senior Developer en Engineering
💰 Salario: $150,000
CREATE TABLE companies (
id INTEGER PRIMARY KEY,
name VARCHAR NOT NULL,
email VARCHAR NOT NULL,
-- Dirección principal (embebida con prefijo)
main_address_street VARCHAR,
main_address_city VARCHAR,
main_address_zipCode VARCHAR,
main_address_country VARCHAR,
-- Dirección de facturación (embebida con prefijo)
billing_address_street VARCHAR,
billing_address_city VARCHAR,
billing_address_zipCode VARCHAR,
billing_address_country VARCHAR,
-- Arrays y JSON como texto
tags TEXT,
settings TEXT,
isActive BOOLEAN DEFAULT 1
);INSERT INTO companies VALUES (
1,
'TechCorp SA',
'contact@techcorp.com',
-- main_address_*
'Av. Corrientes 1234',
'Buenos Aires',
'C1043AAZ',
'Argentina',
-- billing_address_*
'San Martín 567',
'Córdoba',
'X5000',
'Argentina',
-- transformers
'technology,software,innovation',
'{"theme":"dark","notifications":true}',
1
);- Objetos embebidos simplifican - Menos tablas, consultas más directas
- Prefijos evitan colisiones - Múltiples objetos del mismo tipo
- Transformers son poderosos - Mapeo automático de tipos complejos
- Métodos de negocio - Lógica en los objetos embebidos
- Performance vs flexibilidad - Trade-off importante a considerar