È possibile eseguire più condizioni di join con l'operatore di pipeline di aggregazione $lookup
nella versione 3.6 e successive.
Abbiamo bisogno di assegnare i valori dei campi alla variabile usando il campo opzionale let
; si accede quindi a tali variabili nelle fasi di campo pipeline
in cui si specifica la pipeline da eseguire sulle raccolte.
Si noti che nella fase $match
, si utilizza l'operatore di query di valutazione $expr
per confrontare il valore dei campi.
L'ultima tappa in cantiere è la fase gasdotto $replaceRoot
aggregazione dove abbiamo semplicemente fondiamo il risultato $lookup
con parte del documento $$ROOT
utilizzando l'operatore $mergeObjects
.
db.collection2.aggregate([
{
$lookup: {
from: "collection1",
let: {
firstUser: "$user1",
secondUser: "$user2"
},
pipeline: [
{
$match: {
$expr: {
$and: [
{
$eq: [
"$user1",
"$$firstUser"
]
},
{
$eq: [
"$user2",
"$$secondUser"
]
}
]
}
}
}
],
as: "result"
}
},
{
$replaceRoot: {
newRoot: {
$mergeObjects:[
{
$arrayElemAt: [
"$result",
0
]
},
{
percent1: "$$ROOT.percent1"
}
]
}
}
}
]
)
Questa rendimenti gasdotti qualcosa che assomigliano a questo:
{
"_id" : ObjectId("59e1ad7d36f42d8960c06022"),
"user1" : 1,
"user2" : 2,
"percent" : 0.3,
"percent1" : 0.56
}
Se non si è in versione 3.6 e versioni successive, è possibile prima aderire utilizzando uno del vostro campo diciamo "user1" poi da lì si svolge la matrice del documento corrispondente utilizzando l'operatore di pipeline di aggregazione $unwind
. La fase successiva della pipeline è la fase $redact
in cui si escludono quei documenti in cui il valore di "utente2" dalla raccolta "unita" e il documento di input non sono uguali utilizzando le variabili di sistema $$KEEP
e $$PRUNE
. È quindi possibile rimodellare il documento nello stage $project
.
db.collection1.aggregate([
{ "$lookup": {
"from": "collection2",
"localField": "user1",
"foreignField": "user1",
"as": "collection2_doc"
}},
{ "$unwind": "$collection2_doc" },
{ "$redact": {
"$cond": [
{ "$eq": [ "$user2", "$collection2_doc.user2" ] },
"$$KEEP",
"$$PRUNE"
]
}},
{ "$project": {
"user1": 1,
"user2": 1,
"percent1": "$percent",
"percent2": "$collection2_doc.percent"
}}
])
che produce:
{
"_id" : ObjectId("572daa87cc52a841bb292beb"),
"user1" : 1,
"user2" : 2,
"percent1" : 0.56,
"percent2" : 0.3
}
Se i documenti nelle raccolte hanno la stessa struttura e ti ritrovi di eseguire questa operazione spesso, allora si dovrebbe considerare di fondere le due collezioni in uno o inserire i documenti in queste raccolte in una nuova raccolta.
db.collection3.insertMany(
db.collection1.find({}, {"_id": 0})
.toArray()
.concat(db.collection2.find({}, {"_id": 0}).toArray())
)
Poi $group
i documenti di "user1" e "user2"
db.collection3.aggregate([
{ "$group": {
"_id": { "user1": "$user1", "user2": "$user2" },
"percent": { "$push": "$percent" }
}}
])
che produce:
{ "_id" : { "user1" : 1, "user2" : 2 }, "percent" : [ 0.56, 0.3 ] }
No, non è possibile unire utilizzando 'user1' e 'user2' questo semplicemente non è possibile in quanto sia 'localField' che' foreignField' prendono solo il nome di un campo. – styvane
Ho trovato un modo per farlo. raccolta in una nuova raccolta e raggrupparla – user6148078