Je veux interroger un sous-document qui vit dans un document parent et seulement sélectionner (retourner dans la réponse express) un sous-document spécifique avec ses propres données, mais de la façon dont je le fais, il sélectionne/renvoie tous les sous-documents, sans filtrer celui dont j'ai besoin, que j'essaie de filtrer par le champ candidateId
Voici ma question :
interviewRouter.get(
"/:idCandidato&:userEmail",
async (req: Request, res: Response) => {
const { idCandidato, userEmail } = req.params;
parseInt(idCandidato);
const infoCandidato = await User.find({
email: userEmail,
"candidates.candidateId": idCandidato,
}).select({"_id": 0, "candidates": 1});
infoCandidato
? res.status(200).json({ Candidato: infoCandidato })
: res.status(404).json({ Candidato: "Candidato no encontrado" });
}
);
Voici la structure de mon document et de mon sous-document :
{
"_id" : ObjectId("61223b3c88e21fe0ee69d689"),
"username" : "randomUserName",
"email" : "random@email.com",
"pictureUrl" : "some/url/to/the/user/picture/username",
"role" : "admin",
"candidates" : [
{
"_id" : ObjectId("612242cd11a7f1ebc6a18661"),
"candidateName" : "some candidates name",
"candidateId" : 123,
"candidateInfo" : [
{
"_id" : ObjectId("612242cd11a7f1ebc6a18662"),
"currentSituation" : "3",
"motivationToChange" : "3",
"postSavingDate" : ISODate("2021-08-22T12:27:57.490Z")
},
{
"_id" : ObjectId("612242cd11a7f1ebc6a04854"),
"currentSituation" : "6",
"motivationToChange" : "7",
"postSavingDate" : ISODate("2021-08-22T13:56:57.490Z")
}
],
"availableNow" : false,
"mainSkills" : "MM"
},
{
"_id" : ObjectId("612261abf7b68bfaf56345df"),
"candidateName" : "some other guy",
"candidateId" : 1234,
"candidateInfo" : [
{
"_id" : ObjectId("612261abf7b68bfaf56345e0"),
"currentSituation" : "dunno",
"motivationToChange" : "no idea",
"postSavingDate" : ISODate("2021-08-22T14:39:39.161Z")
}
],
"availableNow" : false,
"mainSkills" : "JavaScript"
}
],
"__v" : 0
}
Ci-dessous, vous pouvez voir ce que ma requête renvoie, qui est en fait l'ensemble candidates
au lieu des sous-documents filtrés dont j'ai besoin. :
{
"Candidato": [
{
"candidates": [
{
"_id" : ObjectId("612242cd11a7f1ebc6a18661"),
"candidateName" : "some candidates name",
"candidateId" : 123,
"candidateInfo" : [
{
"_id" : ObjectId("612242cd11a7f1ebc6a18662"),
"currentSituation" : "3",
"motivationToChange" : "3",
"postSavingDate" : ISODate("2021-08-22T12:27:57.490Z")
},
{
"_id" : ObjectId("612242cd11a7f1ebc6a04854"),
"currentSituation" : "6",
"motivationToChange" : "7",
"postSavingDate" : ISODate("2021-08-22T13:56:57.490Z")
}
],
"availableNow" : false,
"mainSkills" : "MM"
},
{
"_id" : ObjectId("612261abf7b68bfaf56345df"),
"candidateName" : "some other guy",
"candidateId" : 1234,
"candidateInfo" : [
{
"_id" : ObjectId("612261abf7b68bfaf56345e0"),
"currentSituation" : "dunno",
"motivationToChange" : "no idea",
"postSavingDate" : ISODate("2021-08-22T14:39:39.161Z")
}
],
"availableNow" : false,
"mainSkills" : "JavaScript"
}
]
}
]
}
Note importante : rappelez-vous que je veux juste qu'il revienne soit 123
o 1234
sous-document, en fonction du candidateId
Je passe à la requête
Voici une solution de contournement que j'ai trouvée, mais je pense qu'elle est un peu sale et j'apprécierais une autre alternative :
interviewRouter.get(
"/:idCandidato&:userEmail",
async (req: Request, res: Response) => {
const { idCandidato, userEmail } = req.params;
const infoCandidato = await User.findOne(
{
email: userEmail,
"candidates.candidateId": idCandidato,
},
function (err: any, response: any) {
if (err) {
res.status(400).send(err);
} else {
let newResponse = response["candidates"].filter((element: any) => {
return element.candidateId === parseInt(idCandidato);
});
res.status(200).json({ Candidato: newResponse });
}
}
);
Avec cette solution de contournement, j'obtiens ce dont j'ai besoin, mais cela semble un peu désordonné et je pense qu'il pourrait y avoir une autre solution plus propre. Voici ce que j'obtiens en retour :
{
"Candidato": [
{
"_id" : ObjectId("612242cd11a7f1ebc6a18661"),
"candidateName" : "some candidates name",
"candidateId" : 123,
"candidateInfo" : [
{
"_id" : ObjectId("612242cd11a7f1ebc6a18662"),
"currentSituation" : "3",
"motivationToChange" : "3",
"postSavingDate" : ISODate("2021-08-22T12:27:57.490Z")
},
{
"_id" : ObjectId("612242cd11a7f1ebc6a04854"),
"currentSituation" : "6",
"motivationToChange" : "7",
"postSavingDate" : ISODate("2021-08-22T13:56:57.490Z")
}
],
"availableNow" : false,
"mainSkills" : "MM"
},
]
}
Des idées ? Merci.
Problème résolu par @eol - Note simple
Comme indiqué, @eol a résolu le problème et partagé la solution. J'ai pris sa réponse et l'ai traduite en JavaScript/Mongoose sintaxis et voilà :
interviewRouter.get(
"/:idCandidato&:userEmail",
async (req: Request, res: Response) => {
const { idCandidato, userEmail } = req.params;
const infoCandidato = await User.aggregate([
{
"$match": {
email: userEmail
}
},
{
"$unwind": "$candidates"
},
{
"$match": {
"candidates.candidateId": parseInt(idCandidato)
}
}]);
infoCandidato.length !== 0
infoCandidato
? res.status(200).json({ Candidato: infoCandidato })
: res.status(404).json({ Candidato: "Candidato no encontrado" });
}
);