Stack Overflow en español Asked by Alejandro Castellanos on December 26, 2020
estoy trabajando en un proyecto con node con mongoose como ORM y tengo la siguiente coleccion:
lo que quiero hacer es consultar todos los documentos donde el ultimo objeto del arreglo de ‘agents’ sea igual a determinado ObjectId que yo ingrese en la consulta, hay alguna manera de hacerlo con mongoose?
EDIT
si, en efecto lo que necesito es que la consulta me devuelva los documentos donde el ultimo objeto del arreglo de ‘agents’ sea igual al que yo le introduzca en la consulta, es necesario que sea el ultimo
Esta es la coleccion en texto
{
"_id": {
"$oid": "5edeb7a158414800295c8fa5"
},
"consumer": ["[email protected]"],
"newinteractions": 1,
"flows": [
],
"agents": [{
"0": "OjectId(5eb493a40752445d59d03a40)"
}, {
"1": "OjectId(5eb493a20752445d59d03a3f)"
}],
"currentInputInteraction": [],
"topics": ["5e715959d02920001e9c53b9_DLUNNAS_SERVICIO_CLIENTE"],
"project": {},
"currentConsumer": "[email protected]",
"currentChannel": "WHATSAPP",
"channels": {
"WHATSAPP": "[email protected]"
},
"variables": {
"CONSUMER_NAME": {
"label": "Nombre",
"value": "Greyss"
},
"CONSUMER_PROFILE_PICTURE": {
"label": "Imagen de perfil"
},
"OBTAIN_OPTION": {
"label": "Opcion escogida en menú principal",
"value": "2"
},
"SATISFACTION_LEVEL": {
"label": "Nivel de satisfacción con equipo de servicio al cliente",
"value": "3"
}
},
"currentNode": {
"id": "inicio",
"type": "OPTION",
"delay": 200,
"text": ["¿Ahora por favor califica nuestro servicio, ingresa una de las opciones? "],
"next": "@FLOW:Dlunna"
},
"currentFlow": {
"$oid": "5e7448ee65100a002c9e9736"
},
"createdAt": {
"$date": "2020-06-08T22:11:45.381Z"
},
"updatedAt": {
"$date": "2020-07-27T22:12:18.079Z"
},
"__v": 7,
"flowResponse": {
"5e72f7a033880500294e9c64": {
"dlunna_init": "2"
},
"5e715980d02920001e9c53ba": {
"inicio": "3"
}
},
"currentTopic": "5e715959d02920001e9c53b9_DLUNNAS_SERVICIO_CLIENTE",
"currentAgent": {},
"status": "RESOLVED"
}
a lo que he llegado es
let conversations = await Conversation.find({
agents: {
$slice: -1
}
}, {
$or: [{
status: SystemConversationStatus.RESOLVED
},
{
status: SystemConversationStatus.AWATING_RESPONSE
},
]
}).select("currentChannel currentConsumer currentTopic newinteractions project status updatedAt variables")
se que de esta manera solo obtendria el ultimo valor del arreglo, pero no se como hacer la comparacion
PROBLEMA
Se desea filtrar una colección en MongoDB de tal forma que la consulta realizada devuelva todos los documentos que teniendo un campo de tipo Array
, contengan en dicho Array
un documento que satisfaga las siguientes 2 condiciones:
_id
que debe corresponder con el valor pasado en la consulta._id
corresponde al valor pasado en la consulta debe ser el último elemento de la lista. (Ocupa la última posición en el Array
).SOLUCIÓN
La solución es simple y tenemos al menos 2 opciones, usando una consulta (query
) sencilla y luego filtrar el resultado o usando una consulta que me devuelva el resultado directamente desde la Base de Datos
Usando una query
y filtrando
Puedo pedir en mi consulta todos los documentos que contengan en el campo agents
al menos 1 documento cuyo campo _id
coincida con el que estoy buscando. Luego, una vez recibidos todos los datos, puedo filtrar para quedarme solamente con aquellos que tengan como último elemento de la lista el _id
buscado.
Una consulta sencilla sería algo parecida a esta:
// el valor _id que deseo que aparezca en el campo agents:
const filterId = '5eb493a20752445d59d03a3f';
// mi documento de consulta para el método find
const query = {
'agents._id': mongoose.Types.ObjectId(filterId),
//... otras condiciones o filtros
}
// el resultado me garantiza elementos que contengan en su campo agents elementos
// con el id buscado, ahora puedo filtrar para quedarme sólo con los que tienen
// como último elemento el id buscado.
Conversation.find(query)
.then(results => {
let filtered = results.filter(item => {
return item.agents[item.agents.length - 1]._id.toString() === filterId; // <- condición: último elemento de la lista coincide con fiterId.
});
console.log(filtered.agents); // muestra elementos cuyo último valor es el _id deseado
})
.catch(errorHandler);
Como se aprecia en el código, hago uso del método toString()
del tipo ObjectId
. La razón es muy sencilla, el valor de filterId
es un tipo String
y el valor del campo _id
devuelto por la consulta es de tipo ObjectId
. La comparación siempre daría false
si no hago la conversión de tipo (casting) adecuada. En este caso obtengo el valor del campo _id
como un tipo String
y lo comparo con filterId
.
También hago la conversión de tipo adecuada para pasar el valor en el documento de consulta:
'agents._id': mongoose.Types.ObjectId(filterId)
ya que Mongoose no hará la conversión por nosotros. Si no hacemos esta conversión, no se devolverán resultados, ya que la comparación de String
con ObjectId
siempre dará false
.
De esta forma, los documentos obtenidos luego de aplicar el filtro son los que cumplen con las condiciones establecidas.
Usando una consulta directa
Podemos apoyarnos en las capacidades de la base de datos para filtrar los resultados durante la consulta. Para ello haremos uso del operador posicional $
usado en un documento de proyección de nuestra consulta find()
.
Nuestro documento de proyección sería el siguiente:
const projection = {
'agents.$': -1
}
En este caso indico que deseo realizar una comparación con el último elemento de la lista. Las listas (array
) en MongoDB se enumeran desde el valor 0. Sin embargo, usar un índice negativo indica que deseamos recorrerla en orden inverso. Por lo tanto -1
indica el último elemento de la lista, y -2
sería el penúltimo y así sucesivamente.
Ahora la consulta sería parecida a la siguiente:
const filterId = '5eb493a20752445d59d03a3f';
const query = {
'agents._id': mongoose.Types.ObjectId(filterId),
// otros filtros
}
const projection = {
'agents.$': -1
}
Conversation.find(query, projection)
.then(results => {
console.log(results); // <- Sólo tendrá documentos que contengan en la última posición del campo agents el _id buscado
//...
})
.catch(errorHandler);
Espero que esto te ayude a resolver el problema.
Answered by Mauricio Contreras on December 26, 2020
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP