Quiero recuperar los chats de un usuario con los usuarios correspondientes de una colección diferente en NodeJS y MongoDB.
La naturaleza de NodeJS me da la mala sensación de que ejecutar el siguiente código bloqueará o disminuirá el rendimiento de mi aplicación. Puedo duplicar algunos datos pero quiero aprender más sobre NodeJS.
Por favor, hágame saber si mi código está bien y si no disminuirá el rendimiento.
Aquí busco 20 chats. También necesito sus correspondientes usuarios. luego obtengo los userIds de usuario y realizo otra consulta en la colección User . Ahora tengo ambos, pero debería fusionarlos usando Array.map .
No uso $lookup porque mis colecciones están fragmentadas.
$buscar
Realiza una unión externa izquierda a una colección no fragmentada en la misma base de datos para filtrar documentos de la colección "unida" para su procesamiento. Para cada documento de entrada, la etapa $lookup agrega un nuevo campo de matriz cuyos elementos son los documentos coincidentes de la colección "unida". La etapa $lookup pasa estos documentos remodelados a la siguiente etapa. https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/#mongodb-pipeline-pipe.-lookup
let chats = await Chat.find({ active: true }).limit(20); /* [ {_id: ..., userId: 1, title: 'Chat A'}, ... ] */ const userIds = chats.map(item => item.userId); /* [1, ...] */ const users = await User.find({ _id: { $in: userIds }}); /* [ {_id: 1, fullName: 'Jack'}, ... ] */ chats = chats.map(item => { item.user = users.find(user => user._id === item.userId); return item; }); /* [ { _id: ..., userId: 1, user: {_id: 1, fullName: 'Jack'}, // <-------- added title: 'Chat A' }, ... ] */NO es así como debes hacerlo. MongoDB tiene algo llamado Aggregation Framework y $lookup pipeline que lo hará automáticamente con solo 1 consulta MongoDB.
Pero como está usando Mongoose, esta consulta se vuelve aún más simple ya que puede usar el método populate() de Mongoose. Entonces, todo su código se puede reemplazar con una línea como esta:
const chats = await Chat.find({ active: true }).populate('userId;).limit(20); console.log(chats)Nota: si sus colecciones están fragmentadas, en mi opinión, ya implementó la lógica de la mejor manera posible.
Está utilizando async/await, por lo que su código esperará una respuesta cada vez que use await
// Wait to finish here let chats = await Chat.find({ active: true }).limit(20); /* [ {_id: ..., userId: 1, title: 'Chat A'}, ... ] */ // Wait to finish here too const users = await User.find({ _id: { $in: userIds }}); /* [ {_id: 1, fullName: 'Jack'}, ... ] */ Entonces, si tiene demasiados datos y no tiene ningún índice en su colección, será demasiado largo terminar esa consulta. En este caso, debe crear una ref en su colección Chat con el User de la colección con chat.userId = user._id
Luego, cuando llame al chat de consulta, complete el campo userId de usuario para que no tenga que asignar const ID de usuario = populate const userIds = chats.map(item => item.userId); y chats = chats.map...
Ejemplo de esquema de chat
const { Schema, model } = require("mongoose"); const chatSchema = new Schema({ active: Boolean, userId: { type: "ObjectId", ref: "User", }, title: String, message: String // another property }); const userSchema = new Schema({ username: String, email: String // another property }) // query for chat const chatModel = new model('chat', chatSchema) let chats = await chatModel.find({ active: true }).populate('userId').limit(20); /* [ { _id: ..., userId: {_id: 1, fullName: 'Jack'}, // <-------- already have title: 'Chat A' }, ... ] */