PERSISTENCIA DE NUESTROS DATOS

Esta vez, no en ficheros, sino en una base de datos

REPASO

ROUTER

const express = require('express');

const app = express();

// Resources routers 
const usersRouter = require('./api/users');

// Applying middlewares and routes
app.use(express.json());
app.use('/api/users', usersRouter);

app.listen(5000);

router + module.exports

const express = require('express');
const app = express();

// Resources routers 
const usersRouter = require('./api/users');

app.use('/api/users', usersRouter);

server.js

const router = require('express').Router();

router.get('/', ( req, res) => {
    // Code here
});
router.get('/:id', ( req, res) => {
    // Code here
});
router.post('/', ( req, res) => {
    // Code here
});

module.exports = router;

api/users/index.js

Y si ...

const router = require('express').Router();
const magic = require('./whereTheMagicHappens');

router.get('/', magic.doWhatever);
router.get('/:id', magic.doWhatever);
router.post('/', magic.doWhatever);

module.exports = router;

/api/users/index.js

Y si ...

Y si ...

index.js 10 líneas

api/users/index.js 8 líneas

api/users/users.controller.js 60 líneas

PERSISTENCIA DE NUESTROS DATOS

Esta vez, no en ficheros, sino en una base de datos

SQL

NO-SQL

GRAFOS 

¿ WHY MONGO?

Base de datos basada en documentos

Nos permite guardar la información como si de un objeto se tratase.

Los documentos del mismo tipo no están obligados a tener unos campos si o si e incluso estos podrán variar

EJEMPLO

DESCARGAMOS E INSTALAMOS

MONGODB

Si todo ha ido bien ...

Ejecutamos en una terminal 

mongod o la ruta completa al .exe

y nos dirá que está listo y escuchando en el puerto 27017

Si queremos acceder a la consola

Para acceder a la consola de mongo una vez tengamos el mongod corriendo debemos de ejecutar el comando/ejecutable mongo

¡ AL LÍO !

En la terminal "creamos" una db

use NOMBREBD

db.createCollection()

show collections

db.users.insert( { } );

db.users.find( { } );

db.customers.find( { } ).pretty()

db.customers.update( { }, { } )

vs

db.customers.update( { }, { $set : { key : value }  } )

db.customers.update( { }, { } )

db.customers.update( { }, { $set : { key : value }  } )

vs

Machacaría todos los otros atributos

.update( {}, {} , { upsert : true )

.update({},{$rename :{ clave : clave2 }})

db.customers.remove( { } )

db.customers.remove( { }, {justOne : true} )

nuevos métodos 

db.users.insertOne()

db.users.insertMany()

db.users.deleteOne()

db.users.deleteMany()

db.users.updateOne()

db.users.updateMany()

db.users.replaceOne()

query

resultado.sort( { createdAt : 1, other : 0 }) 

resultado.limit( 10 )

resultado.forEach ( ) :O

resultado.map ( ) :O

resultado.count()

query

resultado.sort( { createdAt : 1, other : 0 }) 

resultado.limit( 10 )

resultado.forEach ( ) :O

resultado.map ( ) :O

resultado.count()

Ejercicios

Crea una nueva bd llamada pruebas.
Dentro de ella crea una colleción llamada TODOS e importa el json de jsonplaceholder

 

Realiza los siguientes consultas:

Ejercicios

  • Cuenta el número de to-do's.
  • Cuenta el número de to-do's del usuario 6.
  • Cuenta el número de to-do's que tienen un id mayor del 140.
  • Cuenta el número de to-do's que están completados. 
  • Cambia todos los to-do's del usuario 5 a completed = true.
  • Renombra el atributo title por content.
  • Devuelve los 10 últimos to-do's.
  • Devuelve por consola para los 5 últimos to-do's un mensaje así : "El to-do con el texto 'loquesea' pertenece al usuario con id: 'id'" 

Ejercicios

  • Inserta 10 nuevos to-do's para el usuario con id 88
  • Borra todos los to-do's del usuario 3 y del usuario 4
  • Encuentra los to-do's del usuario 2 y cambiales el id del usuario por el 5

Alternativas a la consola

Conectando mongo con nodejs

mongodb-driver

const mongodb = require('mongodb');

mongodb.connect('mongodb://localhost', function (err, client) {
    if (err) return console.error(err);
    const db = client.db('todolist');
    console.log("Connected successfully to server");
    
    const todosCollection = db.collection('todos');
    todosCollection.find({}).toArray((err, response) => {
        console.log(response);
        client.close();
    })
});
const mongodb = require('mongodb');

mongodb.connect('mongodb://localhost', function (err, client) {
    if (err) return console.error(err);
    const db = client.db('todolist');
    console.log("Connected successfully to server");
    
    const todosCollection = db.collection('todos');
    todosCollection.insertMany([{},{}] , (err, response) => {
        console.log(response.result);
        console.log(response.result.n);
        client.close();
    })
});

Mini ejercicio

Instalar el mongodb-driver y verifica que está todo bien haciendo un find a tu collección de todos e imprimiendo por consola el .length de los todos encontrados

Librerías ODM

Hay módulos que nos permiten interacturar con los Documentos y collecciones de nuestra base de datos como si de objetos y arrays normales se tratasen :O 
const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost/todolist');

var TODOschema = mongoose.Schema({
    text: String,
    id : String,
    createdAt : Number,
    isCompleted : Boolean
});

var TODO = mongoose.model('todo', TODOschema);

TODO.find({}, (err, res) => {
    console.log(res);
})
const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost/todolist');

var TODOschema = mongoose.Schema({
    text: String,
    id : String,
    createdAt : Number,
    isCompleted : Boolean
});

var TODO = mongoose.model('todo', TODOschema);

TODO.find({}, (err, res) => {
    console.log(res);
})
const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost/todolist');

var TODOschema = mongoose.Schema({
    text: String,
    id : String,
    createdAt : Number,
    isCompleted : Boolean
});

var TODO = mongoose.model('todo', TODOschema);

TODO.find({}, (err, res) => {
    console.log(res);
})
var TODO = mongoose.model('todo', TODOschema);

TODO.find({})

TODO.find({createdAt : 1521713274870})

TODO.find({createdAt : { $gt : 1521713274870} })

TODO.find({ otros : { $in : [ {hola : "mundo" } ]} })

// Proyecciones
TODO.find({createdAt : 1521713274870}, "text createdAt" )
Person.
  find({
    occupation: /host/,
    'name.last': 'Ghost',
    age: { $gt: 17, $lt: 66 },
    likes: { $in: ['vaporizing', 'talking'] }
  })
    .limit(10)
    .sort({ occupation: -1 })
    .select({ name: 1, occupation: 1 })
    .exec(callback);

// Using query builder
Person.
  find({ occupation: /host/ })
    .where('name.last').equals('Ghost')
    .where('age').gt(17).lt(66)
    .where('likes').in(['vaporizing', 'talking'])
    .limit(10)
    .sort('-occupation')
    .select('name occupation')
    .exec(callback);

var TODO = mongoose.model('todo', TODOschema);

var nuevo = new TODO({
    text : 'Hello',
    id : "asd",
    createdAt : 13131312313,
    isCompleted : false
})
nuevo.save();

Insertando documentos

TODO.create({ text: 'hola' }, function (err, small) {
  if (err) return res.status(500).json(err);
  // saved!
});
TODO.create({ text: 'hola' }).then(doc) {
  // confirmed
});

Insertando documentos

TODO.create({ text: 'hola' }).then(doc) {
  // confirmed
});

var TODO = mongoose.model('todo', TODOschema);

TODO.findOne ( { "text" : "hola" } , (err , doc) => {
    
    doc.text = 'Nuevo texto';

    doc.save();

}

Actualizando documentos


var TODO = mongoose.model('todo', TODOschema);

TODO.findOne ( { "text" : "hola" })
    .update( { "text" : "adios" } ) 
    .exec()

var TODO = mongoose.model('todo', TODOschema);

TODO.findOne ( { "text" : "hola" } , (err , doc) => {
    
    doc.remove();

}

Borrando documentos


var TODO = mongoose.model('todo', TODOschema);

TODO.findOne( { "text" : "hola" })
  	.remove()

Borrando documentos

Sigamos

Vamos a cobrar más

Vamos a cobrar más

const mongoose = require('mongoose');

var TODOschema = mongoose.Schema({
    text: String,
    id: String,
    createdAt: Number,
    isCompleted: Boolean
});

var TODO = mongoose.model('todo', TODOschema);

module.exports = TODO;

Fichero : /api/todos/todos.model.js

Vamos a cobrar más

const TODOModel = require('./todos.model');


function getAllTODOs(req, res) {
    TODOModel.find()
        .then(response => {
            console.log(response);
            res.json(response);
        })

}

Fichero : /api/todos/todos.controller.js

Vamos a cobrar más

const TODOModel = require('./todos.model');


function getTODOById(req, res) {
    TODOModel.findOne({ id : req.params.id})
        .then(response => {
            res.json(response);
        })
}

Fichero : /api/todos/todos.controller.js

Vamos a cobrar más

const TODOModel = require('./todos.model');

function getTODOById(req, res) {
    TODOModel.findById(req.params.id)
        .then(response => {
            res.json(response);
        })
        .catch(err => {
            res.json(err);
        })
}

Fichero : /api/todos/todos.controller.js

SI USAMOS LOS _ID de mongo quedaría así

Vamos a cobrar más

A currar

Guarda tus datos del proyecto de twitter en mongodb y usa mongoose para conectar tu api con la base de datos. NO HAGAS VALIDACIONES 

¡UN PASO MÁS ALLÁ !

MONGOOSE TE PERMITE PONER VALIDACIONES

const mongoose = require('mongoose');

var TODOschema = mongoose.Schema({
    text: String,
    id: String,
    createdAt: Number,
    isCompleted: Boolean
});

var TODO = mongoose.model('todo', TODOschema);

module.exports = TODO;
var breakfastSchema = new Schema({
      eggs: {
        type: Number,
        min: [6, 'Too few eggs'],
        max: 12
      },
      bacon: {
        type: Number,
        required: [true, 'Why no bacon?']
      },
      drink: {
        type: String,
        enum: ['Coffee', 'Tea'],
        required: function() {
          return this.bacon > 3;
        }
      }
    });

¿Cómo uso esto?

var Breakfast = db.model('Breakfast', breakfastSchema);

var badBreakfast = new Breakfast({
  eggs: 2,
  bacon: 1,
  drink: 'Milk'
});

var error = badBreakfast.validateSync();

console.log(error.errors); 
  // { 
  //   eggs : 'Too few eggs',
  //   drink : '`Milk` is not a valid enum value for path `drink`.'
  // }

Otra ejemplo más

 var userSchema = new Schema({
  phone: {
    type: String,
    validate: {
      validator: function(v) {
        return /\d{3}-\d{3}-\d{4}/.test(v);
      },
      message: '{VALUE} is not a valid phone number!'
    },
    required: [true, 'User phone number required']
  }
});
Aplica las validaciones en tus Schemas
Aplica paginación a la api :O 

queryParams 

investiga como paginar una búsqueda de mongoose 

¡investiga tanto el limit como el skip y parametrízalos ! 

API

FrontEnd

2 caminos

Llegó el momento de hacerle un 

pequeño frontal a ese "twitter" no ? 

Katas

Tenemos trozos de 20 minutos para hacer un todolist front+back

Grupos de 3 que cambian cada ronda