¿Cómo se pueden relacionar entidades en bases de datos relacionales?
La creación de relaciones entre entidades es fundamental en el diseño de bases de datos relacionales. Cuando se trata de relaciones N a N, la mejor práctica es utilizar una tabla intermedia. Esto es esencial para modelar situaciones como la de un usuario que sigue a otro usuario en una red social.
¿Cómo se crea una tabla intermedia en una base de datos?
Para gestionar relaciones N a N, primero necesitas crear una tabla intermedia que contenga los identificadores de las dos entidades que se van a relacionar. Ejemplificaremos esto con una tabla que llamaremos Users_follow:
CREATETABLE Users_follow ( id INTAUTO_INCREMENTPRIMARYKEY, user_from VARCHAR(32), user_to VARCHAR(32));
Esta estructura básica permite registrar quién sigue a quién.
¿Cómo se añaden las claves a la tabla intermedia?
En una tabla intermedia, las claves es bueno que dependan de más de un campo para garantizar la unicidad de cada relación user_from a user_to. Esto se logra configurando las columnas adecuadas como índices combinados.
CREATEUNIQUEINDEX idx_users_follow ON Users_follow (user_from, user_to);
Este índice garantizará que una combinación específica de user_from y user_to no se duplique.
¿Cómo se implementa la funcionalidad de "seguir"?
La funcionalidad de "seguir" requiere ciertas operaciones y verificar los permisos del usuario. Es importante crear una función que maneje esta lógica.
¿Cuál es el flujo para seguir a un usuario?
El primer paso es crear una función que registre la acción de seguir en la tabla Users_follow. Este proceso implica validar al usuario y registrar los datos de la acción.
functionfollowUser(req, res){const userFrom = req.user.id;// ID del usuario que realiza la acción de seguirconst userTo = req.body.userTo;// ID del usuario a seguir// Lógica para añadir a la base de datos database.addUserFollow(userFrom, userTo);// Enviar respuesta exitosa res.status(201).send({message:'Usuario seguido exitosamente'});}
¿Cómo se administra el acceso mediante tokens?
El acceso a esta funcionalidad debe ser administrado mediante tokens de autenticación, asegurando que solo los usuarios permitidos puedan ejecutar la acción de seguir.
En el flujo de trabajo:
Verificar Token: Validar que el token de usuario es correcto.
Ejecutar Acción: Si todo está en orden, permitir el acceso al recurso.
Gestionar Errores: Si hay problemas con la autenticación, responder con un error adecuado.
¿Cómo se maneja una respuesta al seguimiento exitoso?
Una vez que la acción de seguimiento es exitosa, se debe proporcionar una respuesta clara al usuario confirmando la acción:
functionhandleFollowResponse(req, res){ res.status(201).send({status:'success',message:'Acción de seguir registrada'});}
¿Cómo verificar y mostrar quién sigue a quién?
Para obtener una lista de quiénes siguen a un usuario, se puede implementar una consulta que se basa en el ID del usuario, generalmente incluido en el token de acceso. Esto se puede gestionar utilizando la función query.
¿Pasos siguientes?
Una vez implementados los fundamentos, se puede mejorar esta funcionalidad añadiendo características como:
Fecha y hora de seguimiento.
Verificación y mensajes de error más descriptivos.
Optimización de las consultas para gestionar grandes volúmenes de datos.
A medida que avances en su aprendizaje, encontrarás formas más sofisticadas de gestionar estas relaciones. Sigue explorando y mejorando tus habilidades en bases de datos para crear aplicaciones más robustas y eficientes. ¡El conocimiento es poder!
constfollowers=(id)=> store.get(`${TABLE}_follow`,{user_from: id })return{... followers
}
api/components/store/mysql.js
Modifiqué un poco la función de get para que acepte diversos where, presten atención al query:
constget=async(table, where)=>newPromise((resolve, reject)=>{console.log('table', table)console.log('where', where)// console.log(id) connection.query(`SELECT * FROM ${table} WHERE ?`, where,(error, data)=>{if(error){returnreject(error)}console.log(data)resolve(data)})})
Me gustó la funciona de mysql 🔝
A mí también me gusta cómo funciona :D
Creo que en el código hasta acá hay un problema y es que no se puede crear nuevos usuarios.
Esto pasa porque el controller de user siempre le pasa un id a la función upsert de mysql.js.
Al cumplirse (data && data.id) siempre termina haciendo update.
He llegado a la misma conclusión que tú. Tal cual está implementado el flujo de upsert siempre entra por update.
lo pueden resolver consultando el id y si no existe que haga un insert
Si trabajan con mysql, en lugar de setear el id con nanoid seria mejor dejar que lo administre el propio mysql, solo hay que poner el campo id como PRIMARY KEY y AUTO_INCREMENT
Tengo este error en Insomnia🥲
Cannot GET /api/user/follow/123
Alguien que pueda ayudarme?
no estoy seguro, pero creo que el metodo no es GET, sino POST, y sino es POST, de seguro es PUT
Hola Piero, gracias por responder. El error me sale igualmente con POST y con PUT
Para el reto, añadí un GET con la ruta "/follows" en el componente de red de user , el cual**** hace uso del middleware
constfollows=async(id)=>{let promises =[]const rta =await store.query(`${TABLE}_follow`,{user_to: id }) rta.forEach(item=> promises.push(store.query(`${TABLE}`,{id: item.user_from})))const result =(awaitPromise.all(promises)).flat()return result
}
Por ultimo, modifique el método query para retornar todo el arreglo obtenido y no solo su primer elemento
store/mysql.js:
constquery=async(table, qry)=>{returnnewPromise((res,rej)=>{ connection.query(`SELECT * FROM ${table} WHERE ?`, qry,(err, result)=>{if(err)rej(err)res(result)// paso de result[0] a result})})}
De esta forma, cada vez que hagamos una petición GET a la ruta "/api/user/follows" con un Bearer token valido obtendremos un arreglo con todos los usuarios que están siguiendo al usuario propietario de ese token, en caso de no contar con ninguno, obtendremos un arreglo vacío
Hay que tener en cuenta que al modificar el método query de la base de datos, también debemos modificar el método login del controlador del componente auth, ya que este se encuentra esperando un objeto y le estamos entregando un arreglo con ese objeto dentro, por lo que debemos ajustar nuestra lógica sea añadiendo alguna validación o algo por el estilo y accediendo a las propiedades de ese objeto con data[0]
api/components/auth/controller.js:
const data =await store.query(TABLE,{ username })if(!data || data?.length ===0){throwerror('El usuario no coincide',500)}// data[0]```También debemos ajustar el método **query** del **dummy** para retornar un arreglo y no un objeto, de esta forma cuando cambiemos de base de datos no resulte ningún error, pasando de esto ```js
return col.filter(item=> item[key]=== q[key])[0]||null;```a esto ```js
return col.filter(item=> item[key]=== q[key])||null;
Ojala añadieran un curso de Sequelize.
Buenas tardes, es mi impresión o este método para follow no sirve ya que en el store: Mysql tiene quemado la columna ID para llevar a cabo las comparaciones y la tabla: user_follow no cuenta con dicha columna, creo que hay que refactorizar esos mecanismos abstractos y ennviar como parámetro el nombre de las columnas por la cual(es) se desea filtrar. ¿Alguien le ha funcionado tal cual el código del profesor?
si sirve
sirve aun
Estoy trabajando con SQL SERVER libreria mssql y me arroja el siguiente error, al parece no puedo colocar** ?** el signo de pregunta por que no los admite, alguna solución ?
function insertOld(table, data) {
return new Promise((resolve, reject) => {
connection.query(INSERT INTO ${table} SET ?, data, (err, result) => {
if (err) return reject(err);
resolve(result);
})
})
}
me genera el siguiente error:
(node:11224) UnhandledPromiseRejectionWarning: RequestError: Incorrect syntax near the keyword 'SET'.
Las sentencia SQL debería ir entre comillas
connection.query(`INSERT INTO ${table} SET ?`, data,(err, result)=>{
Desde el inicio decidí separar la función upsert en add y update. Tomó más trabajo de inicio pero sabía que me ahorraría temas a futuro. De momento, todo excelente.
Los archivos que subió el profesor tienen errores, verdad? no estoy obteniendo los errores del servidor, en cambio se queda cargando por la eternidad, descargue los archivos del profesor y los archivos parecen mezclados, super extraño
En esta clase he tenido que usar
jwt.sign(JSON.stringify(data), secret)
Porque los datos venian de la BS de datos en lugar de la request. No me funcinaba con:
jwt.sign(data, secret)
✌
No entiendo muy bien la funcion de upsert. Si si se supone que es para registro porque no se hace obligatorio el campo de password?
functiongetFollowers(query){returnnewPromise((resolve, reject)=>{ connection.query(`select u.* from user_follow as f, user as u where u.id = f.user_to and ?`, query,(err, res)=>{if(err)returnreject(err);resolve(res ||null);});});}
El llamado seria asi:
POSThttp://localhost:3000/api/user/followers/
En el caso que pones deberías cambiar el verbo HTTP ya que POST se utiliza más cuando vas a crear algo, y en este caso sólo vas a obtener una lista. En el caso de sólo obtener información utilizarías GET. ;)
si alguien mas le dio este problema al realizar el follow
"ER_BAD_NULL_ERROR: Column 'user_from' cannot be null"
router.post('/follow/:id',secure('follow'),async(req, res, next)=>{try{const data =await controller.follow(req.user.data.id, req.params.id); response.success(req, res, data,201);}catch(error){next(error);}});