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 63

Preguntas 13

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

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 😃

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 “user” 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

También puedes especificar el campo que quieres popular de la entidad que estás relacionando en el mismo .populate(‘chats’, ‘message’)

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(‘chats’, ‘message’)

"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

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

para resolver el error del exec() yo cambie el callback por then/catch de esta forma:
<code>
model
.find(filter)
.populate(“user”)
.exec()
.then((populated) => {
resolve(populated);
})
.catch((error) => {
reject(error);
});
<code>

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"
		]
}

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ó: “modelo”, “store”, “controller” y “network”. Este es el orden seguido en este aporte
1 - components\chat\model.js( modelo )
El “truco” es la correcta definición de las estructuras para su referencia posterior.
En otro lugar de mi modelo he definido el objeto “User”, el cual contiene la propiedad “name”.
En este modelo he creado un objeto con dos elementos: users (una lista de objetos de tipo “User”) y user(un objeto “User”)
Notese que el nombre de los objetos es utilizado posteriormente para realizar la referencia y llenado (“populate”)
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:
{
“users”:[ “6012d20d15f7522bbcb971ff”, “601ad31b9801d3331ca4ce56”],
“user”:“6012df810503881f7c53a098”
}
El resultado del registro en Atlas es el siguiente:
id:ObjectId(“CODIGO”)
\/users. Array
0
:ObjectID(“CODIGO”)
1_:ObjectID(“CODIGO”)
user: ObjectID(“CODIGO”)
_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
}
]
}

Yo tuve un error que me decía que el exec() ya no aceptaba promesas como argumento, que use async / await.
Me quedo asi

async function getMessages(filterUser) {
    let filter = {};

    if (filterUser !== null) {
        filter = { user: filterUser };
    }

    try {
        const populated = await Model.find(filter)
        .populate('user')
        .exec();
        return populated;
    } catch (error) {
        throw new Error(error);
    }
}

En las versiones modernas de Mongoose entiendo que ya no es necesario hacer el .populate y .exec. En mi caso funcionó de la siguiente forma:

function readMessages(filters) {
    const filter = {};

    for (const key in filters) {
        if (filters[key]) {
            filter[key] = filters[key];
        }
    }

    const messages = Model.find(filter).populate('user');

    return messages;
}

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

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!

Tuve un error parece que por la versión de mongoose con el exec

throw new MongooseError(‘Query.prototype.exec() no longer accepts a callback’);

Y la solución fue la siguiente

model.find(filter)
.populate(‘user’)
.then((res) => {
resolve(res);
})
.catch((err) => {
reject(err);
})

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
		}
	]
}

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

si alguno obtiene el siguiente error: exec already no accept callbacks
yo lo solucione de la siguiente manera:

        Model.find(filter)
            .populate('user')
            .exec()
            .then(populated => resolve(populated))
            .catch(err => reject(err))

Se que es una bobada, pero cuando esten creando el modelo de chat, no se les olvide que para que funcione el array, tienen que cambiar las “[ ]”, por unas “{ }”, para que les funcione

Debe de ir Asi:

Se que es una cosa pequeña, pero a veces esos detalles no nos damos cuenta y no dejan avanzar

Si tienen el error new Query.prototype.exec() no longer accepts a callback’;

En las versiones más recientes de mongoose, la función exec() que ejecutamos justo despues de populate() ya no recibe un callback, es decir que ya no se puede usar .exec((error, populated)), por lo tanto hay que modificar el código para que se devuelva una promesa, y también usar un catch para el error. Yo lo implementé así:

async function getMessages(userFilter) {
        return new Promise((resolve, reject) => {
            let filter = {}
            if (userFilter !== null) {
                filter = { user: userFilter };
            }

            try {
                const data = Model.find(filter)
                    .populate('user')
                    .exec();
                resolve(data)
            } catch (error) {
                reject(error)
            }

        })
    }
const mongoose = require('mongoose');
const { Schema, model } = mongoose;

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

const chatModel = model('Chat', chatSchema);

module.exports = chatModel;

esa Inner lo estaba haciendo con aggregate que te permite hacer procedimientos antes de que se retorne la information tanta como tu quieras mejor dicho mongo con node es un mundo de locos.

para esto haremos cambios a nuestro model de message de la siguiente manera

message.js

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

const mySchema = new Schema({
// usando el schema de usuario enviamos a buscar el id del usuario por medio de los Schema
    user: {
        type: Schema.ObjectId,
        ref: 'User',
    },
    message: {
        type: String,
        required: true,
    },
    date: Date,
});

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

luego cambiamos nuestra lógica de store para obtener la información de la base de datos y para ingresar la información del usuario solo como id

store.js

async function getMessages(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);
        });
    });
}

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);
        });        	

“A 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',
    }]
});

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í

{
“error”: “”,
“body”: []
}

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(‘users’)
.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: ‘Users’,
}],
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,‘Unexpected 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 aquell@s 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