Conocer y comprender c贸mo se realizan las conexiones hacia los servidores a trav茅s de internet y sus implicaciones en el desarrollo de servidores

1

Bienvenida y presentaci贸n del curso

2

Qu茅 es Node y c贸mo instalarlo

3

驴Qu茅 son y c贸mo se usan las peticiones HTTP?

4

M茅todos, cabeceras y estados

5

Cuerpo y query de la petici贸n

Crear un servidor HTTP en Javascript, y comenzar a escuchar y responder peticiones desde un cliente .

6

Crear un servidor HTTP desde NodeJS

7

驴C贸mo pueden venir las peticiones?

8

Recibir informaci贸n desde el cliente: Body y Query

9

Informaci贸n contextual: Leer las cabeceras

10

Tipos de respuesta: Vac铆a, plana, con datos y estructurada

11

Respuestas coherentes

12

Servir archivos est谩ticos

13

Errores: C贸mo presentarlos e implicaciones en la seguridad

Comprender y desarrollar la arquitectura b谩sica de un backend en NodeJS, y comunicarse entre m贸dulos

14

Conceptualmente: Rutas, controladores y bases de datos

15

Rutas y capa de red: Responsabilidades y l铆mites

16

Controladores: Definiendo la l贸gica de negocio

17

Almacenando la informaci贸n en una base de datos

Utilizar una base de datos para definir, modelar, almacenar y recuperar la informaci贸n de nuestra aplicaci贸n

18

Tipos de Bases de Datos: Relacionales y No Relacionales

19

Crear y Configurar tu Base de Datos con MongoDB

20

MongoDB: Almacenar y leer datos

21

MongoDB: Actualizar datos

22

MongoDB: Consultar datos

23

MongoDB: Eliminar Datos

24

Gestionar conexiones a la base de datos desde la API

Uso de entidades para crear aplicaciones escalables

25

Escalando la arquitectura: M煤ltiples entidades

26

Relacionando nuestras entidades

27

C贸mo recibir ficheros desde NodeJS

28

Guardar el fichero en el servidor

Conocer el protocolo de websockets, e implementar comunicaci贸n cliente/servidor con SocketIO.

29

WebSockets: Qu茅 son, por qu茅 son interesantes y c贸mo usarlos

30

Manejo de Websockets con NodeJS

31

Conectar la API al servidor de WebSockets

Revisi贸n de lo aprendido, y pr贸ximos pasos

32

Revisi贸n y pr贸ximos pasos

33

Tips para escalar nuestro proyecto

No tienes acceso a esta clase

隆Contin煤a aprendiendo! 脷nete y comienza a potenciar tu carrera

Relacionando nuestras entidades

26/33
Recursos

En esta clase vamos a relacionar la entidad de usuarios con la entidad de mensajes y a su vez crearemos una entidad chat que relacionar谩 estas dos entidades.

Aportes 53

Preguntas 10

Ordenar por:

Los aportes, preguntas y respuestas son vitales para aprender en comunidad. Reg铆strate o inicia sesi贸n para participar.

En el minuto 11:00 se debe corregir la forma en que declaramos el array ya que en javascript los arrays asociativos se hacen por medio de objetos y no directamente en el array.

const mySchema = new Schema({ users:[{ type: Schema.ObjectId, ref: User}] });

Creo que lo que tendr铆amos ser铆a un arreglo de objetos:

users: [{
	type: Schema.ObjectId,
	ref: 'User'
}]

隆Hola a todos!

Esta es mi propuesta al reto:

// network.js
const express = require('express');
const response = require('../../network/response');
const controller = require('./controller');

const router = express.Router();

router.get('/', function (req, res) {
    controller.listChats()
        .then(chatList => {
            response.success(req, res, chatList, 200);
        })
        .catch(error => {
            response.error(req, res, 'Unexpected Error', 500, error);
        })
});

router.post('/', function (req, res) {
    controller.addChat(req.body.users)
        .then(newChat => {
            response.success(req, res, newChat, 201);
        })
        .catch(error => {
            response.error(req, resp, 'Unexpected error', 500, error);
        });
});

module.exports = router;
// controller.js
const store = require('./store');

function addChat(users) {
    if (!users || users.length < 2) {
        return Promise.reject(`Invalid amound of users: ${users.length}`);
    }

    const newChat = {
        users: users
    }

    return store.add(newChat);
}

async function listChats() {
    return new Promise((resolve, reject) => {
        resolve(store.list());
    })
}

module.exports = {
    addChat,
    listChats
}
// store.js
const Model = require('./model');

function addChat(chat) {
    const newChat = new Model(chat);
    return newChat.save();
}

function listChats() {
    let filter = {};

    return new Promise((resolve, reject) => {
        Model.find(filter)
            .populate('users')
            .exec((error, populated) => {
                if (error) {
                    return reject(error);
                }

                return resolve(populated);
            })
    });
}

module.exports = {
    add: addChat,
    list: listChats
}

y a帽ad铆 la ruta en routes.js

Saludos 馃槂

Tambi茅n puedes especificar el campo que quieres popular de la entidad que est谩s relacionando en el mismo .populate(鈥榗hats鈥, 鈥榤essage鈥)

listChats = () => {
    let filter = {};

    return new Promise((resolve, reject) => {
        Model.find(filter)
            .populate('chats', 'message')
            .exec((error, populated) => {
                if(error) {
                    return reject(error);
                }
                return resolve(populated);
            })
    })
}

En lugar de obtener todos los campos de la entidad relacionada:

"chats": [
                {
                    "_id": "5d97be9cbdf7753d3867863e",
                    "user": "5d97a3adeba63f3f9899048e",
                    "message": "Entidades relacionadas",
                    "date": "2019-10-04T21:50:20.258Z",
                    "__v": 0
                },
                {
                    "_id": "5d98d478d4d1bf30f40fd5be",
                    "user": "5d97ba8a220a1131d46e4787",
                    "message": "Ya casi concluimos este grandioso curso de Node.js con Platzi",
                    "date": "2019-10-05T17:35:52.074Z",
                    "__v": 0
                },
                {
                    "_id": "5d98d4b1d4d1bf30f40fd5bf",
                    "user": "5d97bb7b1ab7964ce0a967ee",
                    "message": "Si lo s茅, estoy muy emocionado",
                    "date": "2019-10-05T17:36:49.315Z",
                    "__v": 0
                }
            ],
            "_id": "5d9a3ed6b0d9aa3918467119",
            "__v": 0

Puedes obtener el especificado en .populate(鈥榗hats鈥, 鈥榤essage鈥)

"chats": [
                {
                    "_id": "5d97be9cbdf7753d3867863e",
                    "message": "Entidades relacionadas"
                },
                {
                    "_id": "5d98d478d4d1bf30f40fd5be",
                    "message": "Ya casi concluimos este grandioso curso de Node.js con Platzi"
                },
                {
                    "_id": "5d98d4b1d4d1bf30f40fd5bf",
                    "message": "Si lo s茅, estoy muy emocionado"
                }
            ],
            "_id": "5d9a3ed6b0d9aa3918467119",
            "__v": 0

Hola a todos! 馃憢
Actualmente populate() puede funcionar con un segundo paramentro. Por ejemplo al obtener mensajes:

const messages = await MySchema.find().populate('user', {
	user: true,
	nombre: true,
	apellido: true,
	_id: false
 })
  1. Donde 鈥渦ser鈥 hace referencia al nombre de la collection a traer.
  2. Mientras que 鈥渰 }鈥 y su contenido hace referencia a los items que quieres mostrar cuando se haga un find().

resultado final:

"error": "",
"body": [
	"_id": "616ccd301afa5191e9129b05",
	"user": {
                "user": "Javier0001",
		"nombre": "Javier",
		"apellido": "Apellido"
            },
	"message": "Hola a todos馃憢"
]

Listo! Yo lo hice todo con Async/Await

network.js

const express = require('express')
const router = express.Router()
const response = require('../../network/response')
const controller = require('./controller')

router.get('/', async (req, res) => {
  try {
    const chatsList = await controller.getChats()
    response.success(req, res, chatsList, 200)
  } catch (error) {
    response.error(req, res, 'Unexpected error', 500, error)
  }
})

router.post('/', async (req, res) => {
  try {
    const { users } = req.body
    const newChat = await controller.addChat({ users })
    response.success(req, res, newChat, 201)
  } catch (error) {
    response.error(req, res, 'Informaci贸n inv谩lida', 400, error.message)
  }
})

module.exports = router

controller.js

const store = require('./store')

async function addChat(chat) {
  try {
    if (!chat.users) {
      console.log('[ERROR] [CHAT CONTROLLER] No hay usuarios')
      throw new Error()
    }
    return await store.addChat(chat)
  } catch (error) {
    throw new Error('Datos incorrectos')
  }
}

async function getChats() {
  try {
    return await store.getChats()
  } catch (error) {
    throw new Error('Error al obtener los datos')
  }
}

module.exports = {
  addChat,
  getChats
}

store.js

const Model = require('./model')

async function addChat(chat) {
  try {
    const myChat = new Model(chat)
    return await myChat.save()
  } catch (error) {
    console.log(error.message)
    throw new Error('Error saving')
  }
}

async function getChats() {
  try {
    return await Model.find().populate('users').exec()
  } catch (error) {
    console.log(error.message)
    throw new Error('Unexpected error')
  }
}

module.exports = {
  addChat,
  getChats
}

model.js

const mongoose = require('mongoose')
const Schema = mongoose.Schema

const ChatSchema = new Schema({
  users: [
    {
      type: Schema.Types.ObjectId,
      ref: 'users'
    }
  ]
})

const model = mongoose.model('chats', ChatSchema)
module.exports = model

La gracia de Mongo es que es schema less. 驴Por qu茅 tuvo que borrar los documentos anteriores para que el populate funcione? Qu茅 otra alternativa tenemos para eso? Porque no creo que sea lo m谩s 贸ptimo tener que borrar o modificar los documentos anteriores para hacer que este populate funcione

Creo que hay que hacer un ejemplo pr谩ctico aterrizado a la realidad para poder entender bien los conceptos. En cierto punto del curso me qued茅 perdido preguntando la raz贸n del por qu茅 se abrieron dos m贸dulos, Message y User.

Listo.
network.js

const express = require('express');
const response = require('../../network/response');
const controller = require('./controller');
const router = express.Router();

router.post('/', (req, res) => {
    controller.addChat(req.body.users)
        .then(data => {
            response.success(req, res, data, 201);
        })
        .catch(err => {
            response.error(req, res, 'Internal error', 500, err);
        });
});

router.get('/:userId', (req, res) => {
    controller.listChats(req.params.userId)
        .then(users => {
            response.success(req, res, users, 200);
        })
        .catch(err => {
            response.error(req, res, 'Internal error', 500, err);
        });
});

module.exports = router;

controller.js

const store = require('./store');

function addChat(users) {
    if (!users || !Array.isArray(users)) {
        return Promise.reject('Invalid user list');
    }

    const chat = {
        users: users,
    };
    return store.add(chat);
}

function listChats(userId) {
    return store.list(userId);
}

module.exports = {
    addChat,
    listChats,
}

model.js

const mongoose = require('mongoose');

const Schema = mongoose.Schema;

 const mySchema = new Schema({
     users: [{
         type: Schema.Types.ObjectId,
         ref: "User"
     }]
 });

const model = mongoose.model('Chat', mySchema);
module.exports = model;

store.js

const Model = require('./model');

function addChat(chat) {
    const myChat = new Model(chat);
    return myChat.save();
}

function listChats(userId) {
	return new Promise((resolve, reject) => {
		let filter = {};
		if (userId) {
			filter = {
				users: userId,
			}
		}
	    
	    Model.find(filter)
	    	.populate('users')
	    	.exec((err, populated) => {
	    		if (err) {
	    			reject(err);
	    			return false;
	    		}

	    		resolve(populated);
	    	});
	});
}

module.exports = {
    add: addChat,
    list: listChats,
}

body:

{
	"users": [
			"5ea4f79c98982646fc6c767d",
			"5ea4f7d698982646fc6c767e",
			"5ea74ee2c8e9e63bf059cd5c",
			"5ea7a1f893465e19d0062eb5"
		]
}

No olviden exportar siempre las funciones. A m铆 me pasa, a ti te pasa, a todos nos pasa. - Carlos Hern谩ndez

Que bonito es lo bonito!

Introducci贸n
Hola, luego de varios d铆as intentando completar el componente de chat, finalmente lo pude conseguir. A continuaci贸n resumo el resultado.
Orden de programacion
El profesor siempre ha se帽alado que se debe seguir un orden al momeneto de programar.
En particular recomend贸: 鈥渕odelo鈥, 鈥渟tore鈥, 鈥渃ontroller鈥 y 鈥渘etwork鈥. Este es el orden seguido en este aporte
1 - components\chat\model.js( modelo )
El 鈥渢ruco鈥 es la correcta definici贸n de las estructuras para su referencia posterior.
En otro lugar de mi modelo he definido el objeto 鈥淯ser鈥, el cual contiene la propiedad 鈥渘ame鈥.
En este modelo he creado un objeto con dos elementos: users (una lista de objetos de tipo 鈥淯ser鈥) y user(un objeto 鈥淯ser鈥)
Notese que el nombre de los objetos es utilizado posteriormente para realizar la referencia y llenado (鈥減opulate鈥)
model.js
//iniciar siempre desde el modelo, store, controller, network
const mongoose=require('mongoose');
const Schema = mongoose.Schema; //clase
//crea esquema de base de datos
const mySchema = new Schema({
users:[
{
type: Schema.ObjectId,
ref: "User",
}
],
user:{
type: Schema.ObjectId,
ref: 'User',
}
});
//ahora se asocia el esquema a la coleccion (o tabla)
// en la base de datos
const model= mongoose.model('chats',mySchema);
module.exports=model;

2 - components\chat\store.js (base de datos)
En esta parte, hay que notar la forma como se solicita el llenado de varias propiedades del modelo:
Se utiliza una lista/array
.populate ( ["propiedad1","propiedad2"] ) //forma correcta, completa todas las propiedades de la lista
en lugar de una lista simple
.populate ( "propiedad1","propiedad2" ) //forma incorrecta, solo completa la primera propiedad

store.js
//iniciar siempre desde el modelo, store, controller, network
const Model=require('./model'); //recupera modelo
//convierte a funcion asincrona
function addChat(chat){
const newChat=new Model(chat);
return newChat.save();
}
async function listChats(){
let filter={};//objeto
//return list; //ya no devuelve de mock
return new Promise((resolve, reject)=>{
Model.find( )
.populate(['user','users'])
.exec( (error, populated) =>{
if(error){
reject(error);
return false;
}
resolve(populated);
} );
})
}
module.exports={
add:addChat,
list:listChats,
}

3 - components\chat\controller.js (logica del negocio)
Es sencillo, no reviste mayor complejidad. Solo notar que se incluyen las dos propiedades del objeto del modelo
controller.js
//iniciar siempre desde el modelo, store, controller, network
const store = require('./store');
function addChat(users, user){
if(!users || users.length < 2 || !user){
return Promise.reject(Invalido numero de usuarios: ${users.length}); //no crea promesa devuelve reject
}
const newChat ={
users: users,
user:user,
}
//console.log(newChat);
return store.add(newChat); //store devuelve la promesa
}
function listChats(){
//no requiere validar parametros
return store.list(); //store ya maneja promesas
}
module.exports={
addChat,
listChats,
}

4 - components\chat\network.js (enrutamiento)
Tambi茅n es sencillo y se debe notar la inclusi贸n de las dos propiedades del objeto del modelo
controller.js
//iniciar siempre desde el modelo, store, controller, network
const express= require('express');//solicita paquete express
const response = require('../../network/response');//solicita response estandard
const controller=require('./controller');//solicita controller de paquete message
const router=express.Router();//utiliza router de express
router.post('/', function(req, res){
//console.log(req);
controller.addChat( req.body.users, req.body.user )
.then((newChat)=>{
response.success(req, res, newChat, 201);
})
.catch((err) =>{
response.error(req,res,'internal error', 500,err);
});
})
router.get("/", function(req,res){
//console.log(req);
controller.listChats()
.then((chatList)=>{
response.success(req,res,chatList,200);
})
.catch(e=>{
response.error(req,res,'Unexpected error',500,e);
})
});
module.exports =router;

5 - otros archivos ( \network\routes.js )++
Aqui hay que adicionar la llamada al componente chat
routes.js
const express= require('express');//solicita paquete express
const message= require('../components/message/network');//solicita componente message
const user= require('../components/user/network');//solicita componente user
const chat= require('../components/chat/network');//solicita componente chat
//funcion principal de enrutamiento
const routes= function(server){
server.use('/message', message);//enrutamiento componente message
server.use('/user', user);
server.use('/chat', chat);
}
//exportaciones
module.exports = routes;

6 - insercion de registro (insomnia)++
Antes, obtener los ids de los usuarios a registrar en el chat. en el ejemplo se utilizan algunos de ejemplo
En Insomnia crear un metodo con la siguiente especificacion
Metodo: POST
Url: localhost:3000/chat/
Tipo: JSON
body/contenido:
{
鈥渦sers鈥:[ 鈥6012d20d15f7522bbcb971ff鈥, 鈥601ad31b9801d3331ca4ce56鈥漖,
鈥渦ser鈥:鈥6012df810503881f7c53a098鈥
}
El resultado del registro en Atlas es el siguiente:
id:ObjectId(鈥淐ODIGO鈥)
\/users. Array
0
:ObjectID(鈥淐ODIGO鈥)
1_:ObjectID(鈥淐ODIGO鈥)
user: ObjectID(鈥淐ODIGO鈥)
_v:0
7 - listado de registros (insomnia)++
Antes, obtener los ids de los usuarios a registrar en el chat. en el ejemplo se utilizan algunos de ejemplo
En Insomnia crear un metodo con la siguiente especificacion
Metodo: GET
Url: localhost:3000/chat/
El resultado del metodo es un response de tipo 200 OK con el contenido correctamente llenado con los datos de los usuarios:

{
"error": "",
"body": [
{
"users": [
{
"_id": "6012d20d15f7522bbcb971ff",
"name": "carlos",
"__v": 0
},
{
"_id": "601ad31b9801d3331ca4ce56",
"name": "nuevo",
"__v": 0
}
],
"_id": "601ad3709801d3331ca4ce57",
"user": {
"_id": "6012df810503881f7c53a098",
"name": "jorge",
"__v": 0
},
"__v": 0
}
]
}

Al momento de crear un Schema, mongoose le asigna un id(hash) random, pero podemos ser nosotros quien le asignemos uno con new mongoose.ObjectId y asignarle el valor (por ejemplo el DNI | ID | etc).
Os dejo mas informacion y la documentacion de Mongoose aca:
https://mongoosejs.com/docs/populate.html

Tengo alg煤n error y no me compila igual en insomnio no me guarda los datos en la base de datos, adem谩s el c贸digo no esta disponible aqu铆, alguien mas lo tiene completo para poder ver cual es el error, le agradezco.

Estoy estancado 馃槧

y la otra opcionque no sea borrar manualmente de la base de datos cual es?

Luego que segui avanzando en el curso empece a tener un monton de error y tuve que que hacer revert en los commit para literalmente empezar de cero con el componente chat.

Espero su respuesta

mySchema queda as铆:

const mySchema = new Schema({
    users: [{
        type: Schema.ObjectId,
        ref: user
    }]
});

Reto realizado

Para los que est谩n implementando POST y GET
Para los Chats

El body de la consulta POST va as铆

{
	"users": ["61db1bb6a3cbc32d461f9c46", "61db4e588198016f6d2f7ad4", "61db1f94ce73b1298e6c3a10"]
}

Para popular la respuesta de GET

	// Para popular arrays de datos No JSON
	// '.populate' recibe una string vac铆a ('')

        Model.find(filter)
        .populate('')
        .exec((error, populatedData) => {
            if(error){
                return reject(error);
            }

            resolve(populatedData);
        });        	

鈥淎 mi me pasa, a ti te pasar谩, a todos nos pasa鈥 de las mejores frases que he escuchado en el desarrollo de software

Si tienen problemas al intentar colocar el ObjectId del Schema, con el c贸digo

const mySchema = new Schema({
    user: [{
        type: Schema.ObjectId,
        ref: 'User',
    }]
});

intenten con:

const mySchema = new Schema({
    user: [{
        type: Schema.Types.ObjectId,
        ref: 'User',
    }]
});

A mi me funciono sin inconveniente de la primera forma

async function getMessage(userFilter) {

    return new Promise((resolve, reject) => {

        let filter = {}
        if (userFilter !== null) {
            filter = { user: userFilter };
        }
        const messeges = Model.find(filter)
            .populate('user')
            .catch(e => {
                reject(e);
            });
        resolve(messeges);
    });
}

No tuve que eliminar los datos que no ten铆an usuario, respuesta:

{
	"error": "",
	"body": [
		{
			"_id": "61e48fffea845167212e9126",
			"message": "Soy Carlos",
			"date": "2022-01-16T21:37:03.320Z",
			"__v": 0
		},
		{
			"_id": "61e5f5ff2089244da6ab68f3",
			"user": {
				"_id": "61e5f36392453b96504a19c2",
				"user": "Diego",
				"__v": 0
			},
			"message": "Entidades relacionadas",
			"date": "2022-01-17T23:04:31.162Z",
			"__v": 0
		},
		{
			"_id": "61e5f81311968f8620a816b6",
			"user": {
				"_id": "61e5f36392453b96504a19c2",
				"user": "Diego",
				"__v": 0
			},
			"message": "Entidades relacionadas",
			"date": "2022-01-17T23:13:23.196Z",
			"__v": 0
		}
	]
}

Resuelto con async y try catch |

async function getMessages(filterUser) {
  try {
    let filter = {}
    if (filterUser !== null ){
      filter = { user: filterUser }
    }
    const messages = await Model.find(filter).populate('user')
    return messages;
  } catch (error) {
    console.log(error)
  }
}

No cre铆a en la magia hasta el d铆a de hoy (?

Si ya tengo entidades relacionadas, 驴 no seria mejor tener un base de datos relacional ?

Recuerden que dentro de un array va un objeto

const mongoose = require('mongoose');

const Schema = mongoose.Schema;

const mySchema = new Schema({
   users: [
       {
        type: Schema.ObjectId,
        ref: 'User'
       }
   ]
});

const model = mongoose.model('Chat', mySchema);
module.exports = model;

Saben porque insomnia me devuelve el body as铆

{
鈥渆rror鈥: 鈥溾,
鈥渂ody鈥: []
}

dejo fragmentos del code

-----message/store.js

async function getMessages(filterUser) {
return new Promise ((resolve, reject)=> {
let filter = {};
if (filterUser !== null){
filter = { user: filterUser};
}
Model.find(filter)
.populate(鈥榰sers鈥)
.exec((err, populated) => {
if (err){
reject (err)
return false
}
resolve (populated)
})
})

}

------message/controller.js----

async function getMessages(filterUser) {
return new Promise ((resolve, reject) => {
resolve (store.list(filterUser))
})
}

-----message/model.js----

const mySchema = new Schema({
user: [{
type: Schema.ObjectId,
ref: 鈥楿sers鈥,
}],
message: {
type: String,
required: true,
},
date: Date,
})

-------message/network.js----

router.get(鈥/鈥, function(req, res){
controller.getMessages()
.then((messagelist)=> {
response.success(req,res,messagelist,200)
})
.catch(e => {
response.error(req,res,鈥楿nexpected Error鈥, 500, e)
})
})

mi codigo en network.js asi:

router.get('/', (req, res) => { controller.listUser() .then(users => { response.success(req, res, users, 200); }) .catch(er => { response.error(req, res, 'Internal Error', 500, er); }); });

el resto esta igual

literalmente estoy estancado aqu铆

Populater informaci贸n? Al fin todo es relacionado

Mi respuesta al Reto:
Network:

const express = require('express')
const controller  = require('./controller')
const response = require('../../network/response')  
const router = express.Router()

router.route("/")
.all((req, res, next) => {
    console.log("Accedo a la ruta /chat")
    next()
})
.post(async (req, res) => {
    try{
        let users = req.body.users.split(",")            
        const newChat = await controller.createChat(users)
        console.log(newChat)
        response.success(req, res, 201, newChat)
    }catch(error){
        console.log(error)
        response.error(req,res,null,error)
    }
})
.get(async (req, res) => {
    try{
        const chatList = await controller.chatList(null)
        response.success(req, res, null, chatList)
    }
    catch(error){
        response.error(req, res, 500, error)
    }
})

router.get('/:id', async (req, res) => {
    try{
        const chatId = req.params.id || null;
        const chatList = await controller.chatList(chatId)
        response.success(req, res, null, chatList)
    }
    catch(error){
        response.error(req, res, 500, error)
    }
})

module.exports = router;

Controller:

const store = require('./store')

function createChat(users){
    return new Promise((resolve, reject) => {
        if(!users){
            console.error(`[chatController] Invalid Data`)
            reject('La informaci贸n no es correcta')    
            return false; //Este return se utiliza para terminar la ejecucion de la promesa          
        }

        if(users.length == 0){
            console.error(`[chatController] Empty Array`)
            reject('La informaci贸n no es correcta')    
            return false; //Este return se utiliza para terminar la ejecucion de la promesa          
        }

        const newChat = {
            users: users
        }
              
        store.create(newChat)

        resolve(newChat)
    })
}

function chatList(chatId){
   return store.list(chatId)
}

module.exports = {
    createChat,
    chatList,
    // updateMessage,
    // deleteMessage
}

Store:

const Model = require('./model')

const createChat = function(chat){
    const myChat = new Model(chat)
    return myChat.save()
}

const listChats = function(chatId){
    return new Promise((resolve, reject) => {
        let filter = {};
        if(chatId !== null){
            filter = { _id: chatId }
        }
        Model.find(filter)
        .populate('users')
        .exec((error, populated) => {
            if(error){
                reject(error)
                return false                
            }            

            resolve(populated)
        });
    })
}

module.exports = {
    create: createChat,
    list: listChats
}

Bueno les comparlo la solucion鈥 Para aquellos que les esta constanto no se rindan, miren las soluciones de otros y traten de analizar porque lo hicieron ellos de esa forma

network.js

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

const response = require('../../network/response');
const controller = require('./controller');

router.post('/', (req, res) => {
  controller.addChat(req.body.users)
    .then(newChat => {
      response.success(req, res, newChat, 201);
    })
    .catch(err => {
      response.error(req, res, 'Internal error', 500, err)
    })
})
router.get('/', (req, res) => {
  const filterChat = req.query.chat || null
  controller.getChat(filterChat)
    .then(chats => {
      response.success(req, res, chats, 201);
    })
    .catch(err => {
      response.error(req, res, 'Internal error', 500, err)
    })
})


module.exports = router;

controller.js

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

const response = require('../../network/response');
const controller = require('./controller');

router.post('/', (req, res) => {
  controller.addChat(req.body.users)
    .then(newChat => {
      response.success(req, res, newChat, 201);
    })
    .catch(err => {
      response.error(req, res, 'Internal error', 500, err)
    })
})
router.get('/', (req, res) => {
  const filterChat = req.query.chat || null
  controller.getChat(filterChat)
    .then(chats => {
      response.success(req, res, chats, 201);
    })
    .catch(err => {
      response.error(req, res, 'Internal error', 500, err)
    })
})


module.exports = router;

store.js

const Model = require('./model');

function addChat (chat) {
  const newChat = new Model(chat);
  return newChat.save()
}
//get users
function getChat (chat) {
  return new Promise((resolve, reject) => {

    const filter = {}

    if(chat !== null) {
      filter = {chat: chat}
    }
    Model.find(filter)
        .populate('users')
        .exec((err, populated) => {
          if(err) {
            reject(err)
            return false
          }
          resolve(populated)
        })
  })
}

module.exports = {
  add: addChat,
  list: getChat
}

Reto: ChatComponent

chat/controller.js

const store = require("./store");

function addChat(chat) {
  if (!chat.users) {
    return Promise.reject("Invalid request.");
  }
  return store.add(chat);
}

function getChats() {
  return store.list();
}

module.exports = {
  addChat,
  getChats
};

chat/model.js

const mongoose = require("mongoose");

const Schema = mongoose.Schema;

const mySchema = Schema({
  users: [
    {
      type: Schema.Types.ObjectId,
      ref: "User"
    }
  ]
});

const model = mongoose.model("Chat", mySchema);

module.exports = model;

chat/network.js

const express = require("express");
const responseType = require("../../network/response");
const controller = require("./controller");
const router = express.Router();

router.post("/", function(request, response) {
  const { users } = request.body;
  controller
    .addChat({ users })
    .then(data => {
      responseType.success(request, response, data, 200);
    })
    .catch(error => {
      responseType.error(request, response, "Internal error", 500, error);
    });
});

router.get("/", function(request, response) {
  controller
    .getChats()
    .then(data => {
      responseType.success(request, response, data, 200);
    })
    .catch(error => {
      responseType.error(request, response, "Internal error", 500, error);
    });
});

module.exports = router;

chat/store.js

const Model = require("./model");

function addChat(chat) {
  const newChat = new Model(chat);
  console.log(newChat);
  return newChat.save();
}

async function getChats() {
  return new Promise((resolve, reject) => {
    Model.find()
      .populate("users")
      .exec((error, populated) => {
        if (error) {
          reject(error);
          return false;
        }
        resolve(populated);
      });
  });
}

module.exports = {
  add: addChat,
  list: getChats
};

resultado:

GET 鈥http://localhost:3000/chat

{
    "error": "",
    "body": [
        {
            "users": [
                {
                    "_id": "5e4a0c593d361d3df4d5ff3c",
                    "name": "garestrepop",
                    "__v": 0
                },
                {
                    "_id": "5e4a0c961c10153d2cab8024",
                    "name": "maria.restrepo",
                    "__v": 0
                },
                {
                    "_id": "5e4a0d46ebcf0505883b3c26",
                    "name": "jarango",
                    "__v": 0
                },
                {
                    "_id": "5e4b5142d52a641ad02110f4",
                    "name": "rvanegas",
                    "__v": 0
                }
            ],
            "_id": "5e4cae2757b57013d8a84d11",
            "__v": 0
        },
        {
            "users": [
                {
                    "_id": "5e4a0c593d361d3df4d5ff3c",
                    "name": "garestrepop",
                    "__v": 0
                },
                {
                    "_id": "5e4a0c961c10153d2cab8024",
                    "name": "maria.restrepo",
                    "__v": 0
                }
            ],
            "_id": "5e4cae5857b57013d8a84d12",
            "__v": 0
        }
    ],
    "status": 200
}

como hago si quiero usar populate exec y que el resto de los mensajes sigan guardados

por qu茅 usas ; en javascript?

Donde queda la carpeta con el codigo?

model.js

const mongoose = require('mongoose');

const Schema = mongoose.Schema;

const mySchema = new Schema( {
    user: {
        type: Schema.ObjectId,
        ref: "User"
    },
    message: {
        type: String,
        required: true
    },
    date: Date
});

const model = mongoose.model('Messages', mySchema);

module.exports = model;

store.js

const Model = require('./model');

function addMessage(message) {
    const myMessage = new Model(message);
    myMessage.save();
}

async function getMessage(filterUser) {
    return new Promise((resolve, reject) => {
        let filter = {};
        if (filterUser !== null) {
            filter = { user: filterUser };
        }
        Model.find(filter)
            .populate('user')
            .exec((error, populated) => {
                if (error) {
                    reject(error);
                    return false;
                }
                resolve(populated);
            })
    })
}

async function updateText(id, message) {
    const foundMessage = await Model.findOne({
        _id: id
    });

    foundMessage.message = message;
    const newMessage = await foundMessage.save();
    return newMessage;
}

function removeMessage(id) {
    return Model.deleteOne({
        _id: id
    })
}

module.exports = {
    add: addMessage,
    list: getMessage,
    updateText: updateText,
    remove: removeMessage
}

La salida de mi petici贸n GET

{
  "error": "",
  "body": [
    {
      "users": [
        {
          "_id": "5eac51f92fe5302cf9a035cd",
          "name": "Jaime",
          "date": "2020-05-01T16:44:41.413Z",
          "__v": 0
        },
        {
          "_id": "5eac52032fe5302cf9a035ce",
          "name": "Ericsson",
          "date": "2020-05-01T16:44:51.214Z",
          "__v": 0
        },
        {
          "_id": "5eac520a2fe5302cf9a035cf",
          "name": "Juan",
          "date": "2020-05-01T16:44:58.743Z",
          "__v": 0
        }
      ],
      "_id": "5eac6230d3f633445f0eb1d1",
      "date": "2020-05-01T17:53:52.111Z",
      "__v": 0
    },
    {
      "users": [
        {
          "_id": "5eac51f92fe5302cf9a035cd",
          "name": "Jaime",
          "date": "2020-05-01T16:44:41.413Z",
          "__v": 0
        },
        {
          "_id": "5eac52032fe5302cf9a035ce",
          "name": "Ericsson",
          "date": "2020-05-01T16:44:51.214Z",
          "__v": 0
        }
      ],
      "_id": "5eac6ab693c9044b0df43c12",
      "date": "2020-05-01T18:30:14.084Z",
      "__v": 0
    }
  ]
}

Reto completado 馃槃

store.js

//Models
const Model = require('./model');

/**
 * Create a chat in database
 * @param {array} users  The users in the chat
 */
function createChat(users){
    const chat = new Model(users);
    return chat.save();
}

/**
 * List all the chat availables in database
 */
async function getChats(){
    return await Model.find().populate('users').exec();
}

controller.js

//Store
const store = require('./store');

/**
 * Controller logic for creating chats
 * @param {array} users 
 */
const createChat = (users) => {
    if (!users || !Array.isArray(users) || users.length === 0 ){
        return Promise.reject('Invalid data');
    }
    const usersInChat = {
        users
    }
   
    return store.add(usersInChat);
}

/**
 * Controller logic for listing chats
 */
const getChats = () => {
    return store.list();
}

network.js


/**
 * @route POST /chat/
 * @description Endpoint for creating chat
 * @access public
 */
router.post("/", async (req, res) => {
  const { users } = req.body;
  try {
    const chat = await controller.createChat(users);
    if (chat) {
      response.success(req, res, chat, 201);
    }
  } catch (err) {
    response.error(req, res, "Internal error", 500, err);
  }
});

/**
 * @route GET /chat/
 * @description Endpoint for listing chats
 * @access public
 */
router.get("/", async (req, res) => {
    try {
        const chats = await controller.getChats();
        response.success(req, res, chats);
    }catch(err){
        response.error(req, res, 'Internal error', 500, err);
    }
});
async function getMessage(filterUser){
    return new Promise((resolve, reject)=>{
        let filter = {};
        if(filterUser !== null){
            filter = { user: filterUser };
        }
        Model.find(filter)
        .populate('user')
        .then(data =>{
            resolve(data);
        })
        .catch(e=>{
            reject(e);
        });

    });```

Yo estoy pasando todo a arrow functions y asinc away
Les dejo aqui mi repo
Mi solucion al reto:

Network:

//  Get all chats
router.get('/:userId?', async (req, res) => {
    const userId = req.params.userId;

    try {
        const data = await controller.listChats(userId);
        response.success(req, res, data, 200);
    } catch (error) {
        response.error(req, res, "Error getting messages", 400, error);        
    }
})

//  Create a new Chat
router.post('/', async (req, res) => {
    const { users } = req.body;

    try {
        const data = await controller.createChat(users);
        //  req, res, messageForTheUser, status
        response.success(req, res, data, 201);

    } catch (error) {
        //  req, res, error, status, details
        response.error(req, res, "Error creating a new chat", 500, error);
    }
})

Controller:

const createChat = (users) => {
    if (!users){
        return Promise.reject('Two users needed');
    }
    const newChat = {
        users: users
    }
    //console.log(newChat)
    return storage.CreateChat(newChat);
}

const listChats = (userId) => {
    return new Promise( async (resolve, reject) => {
        try {
            const data = await storage.getChats(userId);
            resolve(data);
        } catch (error) {
            reject(new Error(error));
        }
    });
}

Storage:

const createNewChat = (chat) => {
    const myChat = new Model(chat);
    return myChat.save();
}

const getChats = (userId) => {
    return new Promise ((resolve, reject) => {
        let filter = {}
        if(userId){ // if there is a user id, will create a filter with that id
            filter = {
                users: userId
            }
        }

        //  Here we will recibe our documents created with the users data on it, and not only a reference
        Model.find(filter).populate('users').exec((err, populated) => { 
            if (err) {
                reject(err);
                return false
            } else {
                resolve(populated)
            }
        })
    })
}

Para [email protected] que usen async/await
Con ejecutar el metodo .exec() ya vale. Porque el try recoje el resultado y el catch el error de la promesa.

Dando todo por el curso! :v

en el min 4:25鈥 por que lo vamos a volver una promesa? porque se tiene que ejecutar una callback despues de filtrar un mensaje, que traiga el user del respectivo ID_user鈥 y para evitarmos las callbacks, y tener un codigo mas limpio, usamos Promises.

Yo lo hice casi igual excepto que le puse un filtro, en vez de poner un or en network como este

const filterUser = req.query.name || null;

yo lo hice as铆 en el controller

function getUser(filterUser=null) {
  return store.list(filterUser)
}

No me funciona el populate, alguna otra forma de usarlo? lo comento en cuesti贸n de sintaxis

store.js

const Model = require("./model");

const getChats = (filterChat) => {
  return Model.find();
};

const addChat = (chat) => {
  const myChat = new Model(chat);
  myChat.save();
};

module.exports = {
  list: getChats,
  add: addChat,
};

controller.js

const store = require("./store");

const getChats = (filterChat) => {
  return new Promise((resolve, reject) => {
    resolve(store.list(filterChat));
  });
};

const addChat = (chat) => {
  return new Promise((resolve, reject) => {
    resolve(store.add(chat));
  });
};

module.exports = {
  getChats,
};

network.js

const express = require("express");
const controller = require("./controller");
const response = require("../../network/response");
const router = express.Router();

// GET
router.get("/", (req, res) => {
  const filterChat = req.query.id || null;
  controller
    .getChats(filterChat)
    .then((chatList) => {
      response.success(req, res, chatList, 200);
    })
    .catch((err) => {
      response.error(req, res, "Internal error", 500, err);
    });
});

module.exports = router;
const mongoose = require("mongoose");

const mySchema = new Schema({
  users: [
    {
      type: mongoose.Schema.ObjectId,
      ref: User,
    },
  ],
});

const model = mongoose.model("Chat", mySchema);
module.exports = model;

Mi pr谩ctica:
pero aun no me funciona el c贸digo.

Para los que no les carga la lista asi como lo hizo el profe Carlos, asi fue como a mi me funciono:

function getMessages(query) {
  return new Promise((res, rej) => {
    let filter = {};
    if (query) {
      filter = { user: query };
    }

    const messages = Model.find(filter)
      .populate("user")
      .exec().then(data => data).catch(err => rej(err));
    res(messages);
  });
}

Inicio de la clase, por si ya hiciste el reto

Impresionante esta clase