L'agrégation MongoDB devient exponentiellement compliquée à la minute!
Je suis dans la mesure de $unwind
un tableau imbriqué, puis effectuez un $lookup
par le _id
de chaque objet du tableau imbriqué déroulé. Ma dernière tentative consiste à inverser le déroulement avec $group
. Cependant, je ne suis pas en mesure de reconstruire le tableau intégré d'origine, avec son nom de propriété d'origine, ainsi que le reste des propriétés immédiates d'origine de chaque document.
Voici ma tentative jusqu'à présent:
db.users.aggregate([
{
$unwind: "$profile",
$unwind: {
path: "$profile.universities",
preserveNullAndEmptyArrays: true
}
},
{
$lookup: {
from: "universities",
localField: "profile.universities._id",
foreignField: "_id",
as: "profile.universities"
}
},
{
$group: {
_id: "$_id",
emails: { "$first": "$emails" },
profile: { "$first": "$profile" },
universities: { "$Push": "$profile.universities" }
}
}
]).pretty()
Ce que je reçois est quelque chose comme ceci:
{
"_id" : "A_USER_ID",
"emails" : [
{
"address" : "AN_EMAIL_ADDRESS",
"verified" : false
}
],
"profile" : {
"name" : "NAME",
"company" : "A COMPANY",
"title" : "A TITLE",
"phone" : "123-123-1234",
"disabled" : false,
"universities" : [
{
"_id" : "ID_1",
"name" : "UNIVERSITY_NAME_1",
"code" : "CODE_1",
"styles" : {AN_OBJECT}
}
]
},
"universities" : [
[
{
"_id" : "ID_1",
"name" : "UNIVERSITY_NAME_1",
"code" : "CODE_1",
"styles" : {AN_OBJECT}
}
],
[
{
"_id" : "ID_2",
"name" : "UNIVERSITY_NAME_2",
"code" : "CODE_2",
"styles" : {AN_OBJECT}
}
]
]
}
Il y a 2 problèmes avec ce résultat:
universities
résultant est un tableau de tableaux d'un objet chacun, puisque le $lookup
a renvoyé un tableau d'éléments unique pour l'original $profile.universities
tableau imbriqué. Ce ne devrait être qu'un tableau d'objets.universities
résultant doit prendre sa place d'origine tel qu'il est imbriqué sous profiles
. Je sais pourquoi l'original profile.universities
est ainsi, car j'utilise le $first
opérateur. Mon intention derrière cela est de conserver toutes les propriétés d'origine de profile
, en conjonction avec la conservation du tableau universities
imbriqué d'origine.En fin de compte, ce dont j'ai besoin est quelque chose comme ceci:
{
"_id" : "A_USER_ID",
"emails" : [
{
"address" : "AN_EMAIL_ADDRESS",
"verified" : false
}
],
"profile" : {
"name" : "NAME",
"company" : "A COMPANY",
"title" : "A TITLE",
"phone" : "123-123-1234",
"disabled" : false,
"universities" : [
{
"_id" : "ID_1",
"name" : "UNIVERSITY_NAME_1",
"code" : "CODE_1",
"styles" : {AN_OBJECT}
},
{
"_id" : "ID_2",
"name" : "UNIVERSITY_NAME_2",
"code" : "CODE_2",
"styles" : {AN_OBJECT}
}
]
}
}
Y a-t-il un autre opérateur que je peux utiliser au lieu de $group
pour y parvenir? Ou est-ce que je comprends le but de $group
incorrectement?
Edit: Ceci est le message d'origine, pour le contexte: Si Mongo $ lookup est une jointure externe gauche, alors comment se fait-il qu'il exclut les non documents correspondants?
Parce que le $lookup
l'opérateur produit un champ de tableau, vous devez $unwind
le nouveau champ avant le $group
pipeline pour obtenir le résultat souhaité:
db.users.aggregate([
{ "$unwind": "$profile" },
{ "$unwind": {
"path": "$profile.universities",
"preserveNullAndEmptyArrays": true
} },
{ "$lookup": {
"from": "universities",
"localField": "profile.universities._id",
"foreignField": "_id",
"as": "universities"
} },
{ "$unwind": "$universities" },
{ "$group": {
"_id": "$_id",
"emails": { "$first": "$emails" },
"profile": { "$first": "$profile" },
"universities": { "$Push": "$universities" }
} },
{ "$project": {
"emails": 1,
"profile.name" : 1,
"profile.company": 1,
"profile.title" : 1,
"profile.phone" : 1,
"profile.disabled": 1,
"profile.universities": "$universities"
} }
]).pretty()