DEV Community

Cover image for Iniciando con typeOrm para Nodejs
Manuel Ortega Carcamo
Manuel Ortega Carcamo

Posted on • Edited on

Iniciando con typeOrm para Nodejs

¿Qué es SQL TypeOrm?

TypeORM es un Object-Relational Mapper / Mapping-tool, o un ORM, es decir una librería que los desarrolladores utilizan para crear bases de datos y manipular sus datos sin la necesidad de conocer / usar SQL.

¿Porqué usar un ORM?

Los ORM han ganado popularidad debido a que lidiar con el lenguaje SQL directamente requiere de mucho esfuerzo en la mayoría de los casos. El objetivo del ORM entonces es simplificar la mantención de tus datos.

Básicamente, con un ORM no tendrás que escribir SQL otra vez (95% del tiempo) y podrás trabajar con objetos.

Por ejemplo:

Para insertar un usuario con SQL tienes que escribir:

INSERT INTO user (name, last_name) VALUES ('Juan', 'McDonals');
Enter fullscreen mode Exit fullscreen mode

Con un ORM tu código sigue siendo un código familiar como este:

user = User()
user.name = 'Juan'
user.last_name = 'McDonals'

# agrega el user a la base de datos
user.save();

Enter fullscreen mode Exit fullscreen mode

Basta con que digas: user.save() y todo lo que hayas hecho con tu código se traducirá a código de lenguaje SQL.

Decoradores

TypeOrm utiliza el patrón de diseño llamado decorador para modificar el comportamiento de una clase. Estos decoradores nos sirven para definir los elementos de un modelo, como crear una columna, definir si tiene una llave primaria,etc.

Para construir nuestro modelo utilizaremos los siguientes decoradores que nos proporciona typeOrm.

  • @Entity(): Al usar este decorador, se crea una clase que asigna a una tabla de base de datos.

  • @PrimaryGeneratedColumn() :Indica que la columna es Primary Key y que su valor debe ser autoincrementado. Es posible pasarle un parámetro (‘uuid’) que hace que los valores de esta columna sean cadenas de texto aleatorios en lugar de números enteros secuenciales.

  • @Column(): Una columna común y corriente de la base de datos. Podemos especificar varios parámetros como el tipo (varchar, int, tinyint, decimal), si es obligatoria (nullable: true | false), la longitud máxima (length: int) y muchas cosas más.
    Ver Documentación

  • @CreateDateColumn() y @UpdateDateColumn(): Son decoradores especiales que indican que el valor de estas columnas se asigna automáticamente al crear un nuevo registro o al actualizar uno ya existente respectivamente.

Revisemos las operaciones de base de datos más típica

Creando nuestra base de datos

El primer paso sería definir nuestro modelo

@Entity()
export class Users extends BaseEntity{
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  first_name: string;

  @Column()
  last_name: string;

  @Column({unique: true})
  email: string;

  @Column()
  password: string;

}
Enter fullscreen mode Exit fullscreen mode

INSERT: Insertando un registro en la base de datos


    const usersRepo = getRepository(User);
    const user = usersRepo.create(req.body as ObjectLiteral);  //Creo un usuario

    const result = await usersRepo.save(user); //Grabo el nuevo usuario 

Enter fullscreen mode Exit fullscreen mode

SELECT: Buscando o recuperando registros

Hay 2 formas para devolver data de la base de datos:

    1. Buscar/Recuperar/Devolver todo los registros desde un Table/Model en particular usando `getRepository(MyModel).find()`

2. Buscar/Recuperar/Devolver un solo registro basado en su primary key usando `getRepository(MyModel).findOne({campoBaseDatos: valorBuscado})`
Enter fullscreen mode Exit fullscreen mode
# aqui es como se buscan todas las personas
const users = await getRepository(Users).find();

# aqui es como se busca un grupo de personas con name = alex
const users = await getRepository(Users).find("first_name":"alex");

# aquí es cómo se busca a una persona con id = 3 (solo funciona con las primary key)
const user = await getRepository(Users).findOne(req.params.id:"3");
Enter fullscreen mode Exit fullscreen mode

DELETE: Eliminando un registro de la base de datos.

Todo lo que tiene que hacer es utilizar el método .delete() e indicar el ID del usuario a eliminar.

const users = await getRepository(Users).delete(ID_USER);

Enter fullscreen mode Exit fullscreen mode

UDPATE: Actualizar un registro.

Para actualizar, primero necesitas devolver/seleccionar el registro de la base de datos, luego puedes actualizar la propiedad que desees y grabar.

    const user = await getRepository(Users).findOne(req.params.id); //Busco el usuario en la tabla por el ID recibido
    getRepository(Users).merge(user, req.body);  // Hace un merge de los datos existentes con los que se reciben a través de body
    const results = await getRepository(Users).save(user);  // Almacena el cambio en la base de datos
Enter fullscreen mode Exit fullscreen mode

Relaciones

Uno a uno

En ingles one-to-one se utiliza el decorador @OneToOne,es una relación en la que A contiene una instancia de B y B contiene una instancias de A.

Por ejemplo, tomemos las entidades User y Profile. El usuario puede tener solo un perfil y un perfil es propiedad de un solo usuario.

import {Entity, PrimaryGeneratedColumn, Column} from "typeorm";

@Entity()
export class Profile {

    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    gender: string;

    @Column()
    photo: string;

}
import {Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn} from "typeorm";
import {Profile} from "./Profile";

@Entity()
export class User {

    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    name: string;

    @OneToOne(() => Profile)
    @JoinColumn()
    profile: Profile;

}
Enter fullscreen mode Exit fullscreen mode
  • Para almacenar este tipo de relación: a continuación veremos un ejemplo donde se crean una instancia de Profile, luego se crea una instancia del usuario y Profile se asigna a la entidad User.
const profile = new Profile();
profile.gender = "male";
profile.photo = "me.jpg";
await connection.manager.save(profile);

const user = new User();
user.name = 'Joe Smith';
user.profile = profile;
await connection.manager.save(user);
Enter fullscreen mode Exit fullscreen mode

Muchos a uno o uno a muchos

En ingles many-to-one donde se utiliza el decorador @ManyToOne o one-to-many que utiliza le decorador @OneToMany. Este tipo de relación definie que una entidad A contiene múltiples instancias de B, pero B contiene solo una instancia de A

En el siguiente ejemplo se define la entidad User que puede tener varios registros de la entidad Photo , pero cada foto es propiedad de un solo dueño.

import {Entity, PrimaryGeneratedColumn, Column, ManyToOne} from "typeorm";
import {User} from "./User";

@Entity()
export class Photo {

    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    url: string;

    @ManyToOne(() => User, user => user.photos)
    user: User;

}
import {Entity, PrimaryGeneratedColumn, Column, OneToMany} from "typeorm";
import {Photo} from "./Photo";

@Entity()
export class User {

    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    name: string;

        # aqui definimos la relación one-to-many y se especifica la relación con la entidad User
    @OneToMany(() => Photo, photo => photo.user)
    photos: Photo[];

}

Enter fullscreen mode Exit fullscreen mode
  • Para almacenar este tipo de relación: a continuación veremos un ejemplo donde se crean las instancias de las fotos y luego se asignan como un array a la entidad User
const photo1 = new Photo();
photo1.url = "me.jpg";
await connection.manager.save(photo1);

const photo2 = new Photo();
photo2.url = "me-and-bears.jpg";
await connection.manager.save(photo2);

const user = new User();
user.name = "John";
user.photos = [photo1, photo2];
await connection.manager.save(user);

Enter fullscreen mode Exit fullscreen mode

Muchos a muchos

En ingles Many-to-many se utiliza el decorador @ManyToMany,es una relación en la que A contiene varias instancias de B y B contiene varias instancias de A.

Un ejemplo es la relación existente entre una entidades Pregunta con otra Categoría. Una pregunta puede tener varias categorías y cada categoría puede tener varias preguntas.

import {Entity, PrimaryGeneratedColumn, Column} from "typeorm";

@Entity()
export class Category {

    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    name: string;

}

@Entity()
export class Question {

    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    title: string;

    @Column()
    text: string;

    @ManyToMany(() => Category, { 
            cascade: true 
        })

    @JoinTable()
    categories: Category[];

}
Enter fullscreen mode Exit fullscreen mode

@JoinTable() se utiliza para definir la entidad propietaria en la relación. Ene ste ejemplo se debe utilizar el decorador @ManyToMany.

  • Para almacenar una relación @ManyToMany: a continuación veremos une ejemplo donde se crean las instancias de las categorías y luego se asignan como un array a la entidad Question
const category1 = new Category();
category1.name = "animals";
await connection.manager.save(category1);

const category2 = new Category();
category2.name = "zoo";
await connection.manager.save(category2);

const question = new Question();
question.title = "dogs";
question.text = "who let the dogs out?";
question.categories = [category1, category2];
await connection.manager.save(question);
Enter fullscreen mode Exit fullscreen mode
  • Eliminar la una relación @ManyToMany:

Para eliminar una relación de varios a varios entre dos registros, elimínela del campo correspondiente y guarde el registro.

const question = getRepository(Question);
question.categories = question.categories.filter(category => {
    category.id !== categoryToRemove.id
})
await connection.manager.save(question)
Enter fullscreen mode Exit fullscreen mode

¿Listo para empezar a codificar?

Hemos preparado este ejemplo de codificación en vivo que puede ejecutar tu mismo en Gitpod y utilizarlo como base para su proyecto.

Expressjs Rest Hello: https://github.com/4GeeksAcademy/expressjs-rest-hello

Top comments (0)