Tengo dos modelos simples definidos en Mongoose, compuestos por dos esquemas Client y City, tengo la propiedad city definida en Client como ObjectId, ref: 'City', hasta ahora todo bien.
Si busco un cliente y también quiero filtrar por la propiedad 'provincia' de Ciudad, hago esto:
const client = await Client .find({ name: "Gérard" }) .populate([{ path: 'city', model: City, match: { province: 'BA' } }]);Y la salida está bien:
{ "id": "627264e3ec261a883d42ead9", "name": "Gérard", "email": "gerard@depardieu.fr", "date": "1948-12-27", "active": true, "city": { "id": "627264e3ec261a883d42ead1", "name": "Buenos Aires", "province": "BA" } }Sin embargo, si introduzco un código de provincia de una ciudad inexistente:
const client = await Client .find({ name: "Gérard" }) .populate([{ path: 'city', model: City, match: { province: 'CA' } }]);Me devolvería que:
{ "id": "627264e3ec261a883d42ead9", "name": "Gérard", "email": "gerard@depardieu.fr", "date": "1948-12-27", "active": true, "city": null }En este escenario en particular, no quiero que se devuelva ninguna instancia de Client, y no sé cómo evitar este comportamiento con Mongoose, un comportamiento del que nunca tuve que preocuparme con Spring Data, por ejemplo.
¿Algún consejo para mí?
Gracias por adelantado.
Lo resolví yo mismo, tuve que bajar un poco el nivel con Mongoose y usar agregados y búsquedas.
const client = await Client.aggregate([ { $match: { name: "Gérard" } }, { $lookup: { from: City.collection.name, pipeline: [ { $match: { province: 'BA' } } ], as: "city" } }, { $unwind: "$city" }, { $match: { city: { $ne: [] } } } ]);Resultado Esperado:
{ "id": "627264e3ec261a883d42ead9", "name": "Gérard", "email": "gerard@depardieu.fr", "date": "1948-12-27", "active": true, "city": { "id": "627264e3ec261a883d42ead1", "name": "Buenos Aires", "province": "BA" } }La bruja está bien, el cliente de nombre "Gérard" vive en "Buenos Aires", ubicado en la provincia "BA".
Por otra parte:
const client = await Client.aggregate([ { $match: { name: "Gérard" } }, { $lookup: { from: City.collection.name, pipeline: [ { $match: { province: 'CA' } } ], as: "city" } }, { $unwind: "$city" }, { $match: { city: { $ne: [] } } } ]);No devuelve nada, una vez que la ciudad de "Buenos Aires" no se encuentra en la provincia "CA".
Observe aquí el último parámetro (como un objeto) que recibe la matriz pasada a Client.aggregate():
{ $match: { city: { $ne: [] } } }Esto le dice a MongoDB que para devolver datos, la ciudad no debe ser igual a una matriz vacía.
Y con eso el problema está resuelto.