sql >> Database teknologi >  >> NoSQL >> MongoDB

Mongoose.aggregate(pipeline) linker flere samlinger ved hjælp af $unwind, $lookup, $group

Dette var en vanskelig en for en ny til MongoDb 's aggregat . Jeg vil opdele mit svar i trin for at demonstrere for andre, der forsøger at samle en matrix med henvisning til flere samlinger.

Trin 1 - $match for at filtrere på indsamling

$match accepterer de samme forespørgsler som db.collection.find({}) og returnerer en række matchende resultater i tilfældet nedenfor, vælger jeg 4 specifikke poster her

  {'$ match':{_id:{'$ in':[objectId ('5f7bdb3eea134b5a5c976285'), objectId ('5f7bdb3eea134b5a5c976283'), objectId (5f7bdb3eea134b5a5c976284f ( } }} 
$match Result
[ { _id:ObjectId('5f7be0b37e2bdf5b19e4724d'), navn:'CAPTAIN_SAIL', classes:[ 'sail' ], licens:'WC-1', watercraftContexts:[ { _id:ObjectId( '5f7be0b37e2bdf5b19e47241'), watercraftType:'Sailboat', ref:'sailboats' } ], __v:0 }, { _id:ObjectId('5f7be0b37e2bdf5b19e4724e', class:YA, 'CAPTAIN', class:YA',') 'WC-2', watercraftContexts:[ { _id:ObjectId('5f7be0b37e2bdf5b19e47242'), watercraftType:'Yatch', ref:'yatches' } ], __v:0 }, { _id:ObjectId('5f7be49b401,7f7b49b401), navn:5f7be4b401,7f7be401, 'CAPTAIN_SHIP', klasser:[ 'ship' ], licens:'WC-3', watercraftContexts:[ { _id:ObjectId('5f7be0b37e2bdf5b19e47243'), watercraftType:'Ship', ref:'ships' } ], __v:0 }, { _id:ObjectId('5f7be0b37e2bdf5b19e47253'), navn:'CAPTAIN_SAIL_YATCH_SHIP', klasser:[ 'sail', 'yatch', 'ship' ], licens:'WC-7', watercraftContexts:O [ { _id:bjectId('5f7be0b37e2bdf5b19e4724a'), watercraftType:'Sailboat', ref:'sailboats' }, { _id:ObjectId('5f7be0b37e2bdf5b19e4724b'), 'watercraftType', '7beId:'7b:ObjectType', '7beId:'7beId', '7beId', '7beId', '7b:7b, '7b:'), watercraftType:'Ship', ref:'ships' } ], __v:0 }] 

Trin 2 - $slap af, så vi kan iterere med $loopup

I dette resultatsæt er der en matrix af objekter med { _id:, watercraftType: } for at sløjfe over arrayet og forbinde hvert af disse objekter med deres respektive samlingsposter, skal vi opdele arrayet i individuelle uafhængige poster. $unwind funktion vil oprette et nyt datasæt til det næste samlede trin

 { '$unwind':'$watercraftContexts' }, 
$unwind Resultat

Som du kan se $unwind opretter nu en post med en enkelt watercraftContext vi er nu indstillet til at bruge $lookup

[ { _id:ObjectId('5f7be2231da37c5b5915bf9b'), navn:'CAPTAIN_SAIL', classes:[ 'sail' ], licens:'WC-1', watercraftContexts:{ _id:ObjectId('5f7be22531f19) , watercraftType:'Sailboat', ref:'sailboats' }, __v:0 }, { _id:ObjectId('5f7be2231da37c5b5915bf9c'), navn:'CAPTAIN_YATCH', klasser:[ 'yatch' ], licens:'WC-2':, watercraftContexts:{ _id:ObjectId('5f7be2231da37c5b5915bf90'), watercraftType:'Yatch', ref:'yatches' }, __v:0 }, { _id:ObjectId('5f7be2231da915c5c5b class:CAPTAIN'), 'SHIP:CLASS:CAPT'es:'ship' ], licens:'WC-3', watercraftContexts:{ _id:ObjectId('5f7be2231da37c5b5915bf91'), watercraftType:'Ship', ref:'ships' }, __v:0 }, { _id:ObjectId('51b37da('51b37da('51b37da2c51b37da331b37da331b37da) '), navn:'CAPTAIN_SAIL_YATCH_SHIP', klasser:[ 'sail', 'yatch', 'ship' ], licens:'WC-7', watercraftContexts:{ _id:ObjectId('5f7be2231da37c5b5915bf98'), watercraftType:'Sailboat', ref:'sailboats' }, __v:0 }, { _id:ObjectId('5f7be2231da37c5b5915bfa1'), navn:'CAPTAIN_SAIL_YATCH_SHIP', klasser:[ 'sail', 'ship' ],' licens:'WC-7', watercraftContexts:{ _id:ObjectId('5f7be2231da37c5b5915bf99'), watercraftType:'Yatch', ref:'yatches' }, __v:0 }, { _id:ObjectId('5f7372c3da name'), 'CAPTAIN_SAIL_YATCH_SHIP', klasser:[ 'sail', 'yatch', 'ship' ], licens:'WC-7', watercraftContexts:{ _id:ObjectId('5f7be2231da37c5b5915bf9a'), watercraftType:'Ship', ref:'ship' ' }, __v:0 } ] 
Trin 4 $lookup - Slutter sig til hver post fra den udenlandske samling

Det er vigtigt at bemærke, at vi skal $unwind før du kalder $lookup for hver anden samling, vi skal være med. Da vi ønsker at forbinde flere samlinger, er vi nødt til at gemme resultatet i en indsigelse, der er indtastet af samlingen til senere aggregering.

 // Udfører kun $lookup på 'ships'-samling { '$lookup':{ from:'ships', // Collection Name - Note:Gentag for hver samling localField:'watercraftContexts._id', / / Feltet med id til at linke fremmedFelt:'_id', // Feltet på den udenlandske samling skal matche som:'watercrafts.ships' // Stien, hvor opslagsresultatet skal gemmes } } 

Trin 5 - Gentag $unwind og $lookup for de andre joins

Gentag ovenstående til trinene for de yderligere joinforbindelser, og indtast samlingens navn. Jeg har kombineret de samlede stadier for at demonstrere gentagelsen.

 { '$unwind':'$watercraftContexts' }, { '$lookup':{ from:'yatches', localField:'watercraftContexts._id', foreignField:'_id', as:'watercrafts. yatches' } }, { '$unwind':'$watercraftContexts' }, { '$lookup':{ from:'sailboats', localField:'watercraftContexts._id', foreignField:'_id', as:'watercrafts.sailboats ' } } 
Trin 4 og 5 resultater

Hvis du ser godt efter, bemærker du, at en af ​​Captain records eksisterer 3 gange med en anden watercraftType . $lookup vil kun returnere poster, der matcher det specifikke samlingsnavn. Dette er grunden til at gemme dem i et Objekt indtastet af collectionName

[ { _id:ObjectId('5f7be7145320a65b942bb450'), navn:'CAPTAIN_SAIL', classes:[ 'sail' ], licens:'WC-1', watercraftContexts:{ _id:ObjectId('5f7be714544400264544420'5f7be7145439) , watercraftType:'Sailboat', ref:'sailboats' }, __v:0, watercrafts:{ ships:[], yatches:[], sejlbåde:[ { _id:ObjectId('5f7be7145320a65b942bb444'), class:'sail' navn:'Borte med vinden', __v:0 } ] } }, { _id:ObjectId('5f7be7145320a65b942bb451'), navn:'CAPTAIN_YATCH', klasser:[ 'yatch' ], licens:'WC-2', watercraftContexts :{ _id:ObjectId('5f7be7145320a65b942bb445'), watercraftType:'Yatch', ref:'yatches' }, __v:0, vandfartøjer:{ ships:[], yatches:[ { _id:ObjectId('45f39427a class667be'5b), class :'yatch', navn:'Liquid Gold', __v:0 } ], sejlbåde:[] } }, { _id:ObjectId('5f7be7145320a65b942bb452'), n ame:'CAPTAIN_SHIP', klasser:[ 'ship' ], licens:'WC-3', watercraftContexts:{ _id:ObjectId('5f7be7145320a65b942bb446'), watercraftType:'Ship', ref:'ships' }, __v:0 , vandfartøjer:{ skibe:[ { _id:ObjectId('5f7be7145320a65b942bb446'), klasse:'skib', navn:'Jenny', __v:0 } ], yatches:[], sejlbåde:[] } }, { _id:ObjectId('5f7be7145320a65b942bb456'), navn:'CAPTAIN_SAIL_YATCH_SHIP', klasser:[ 'sail', 'yatch', 'ship' ], licens:'WC-7', watercraftContexts:{ _id:ObjectId('5f427bT45f427bTea15f427bT45f427bT1000000000000000000000000000000) :'Sailboat', ref:'sailboats' }, __v:0, vandfartøjer:{ ships:[], yatches:[], sejlbåde:[ { _id:ObjectId('5f7be7145320a65b942bb44d'), klasse:'sail', navn:'Swell Shredder', __v:0 } ] } }, { _id:ObjectId('5f7be7145320a65b942bb456'), navn:'CAPTAIN_SAIL_YATCH_SHIP', klasser:[ 'sail ', 'yatch', 'ship' ], licens:'WC-7', watercraftContexts:{ _id:ObjectId('5f7be7145320a65b942bb44e'), watercraftType:'Yatch', ref:'yatches' }, __v:0, vandfartøjer:{ ships:[], yatches:[ { _id:ObjectId('5f7be7145320a65b942bb44e'), class:'yatch', name:'Audrey', __v:0 } ], sejlbåde:[] } }, { _id:ObjectId(' 5f7be7145320a65b942bb456'), navn:'CAPTAIN_SAIL_YATCH_SHIP', klasser:[ 'sail', 'yatch', 'ship' ], licens:'WC-7', watercraftContexts:{ _id:ObjectId('5f7be7145ypShi:watercraft:watercraft:', ref:'skibe' }, __v:0, vandfartøjer:{ skibe:[ { _id:ObjectId('5f7be7145320a65b942bb44f'), klasse:'skib', navn:'Jenny IV', __v:0 } ], yatches:[], sejlbåde:[] } } ]

Trin 6 $project - Brug projekt til at udjævne objektkortet over joinforbindelser

Vi kan bruge projekt til at vælge alle eksisterende data og udjævne objektkortet over sammenføjningsresultater til et enkelt array.

 { '$project':// nøgler med værdien 'true' vil blive inkluderet { navn:true, licens:true, classes:true, _id:true, watercraftContexts:true, __v:true, vandfartøjer :// Gentildeler værdien af ​​vandfartøjer { '$setUnion':// Accepterer en række arrays for at flade [ '$watercrafts.ships', '$watercrafts.yatches', '$watercrafts.sailboats' ] } } } 
$projekt resultat

Resultaterne af ovenstående $project erstatter vandfartøjerne objekt med et fladt array af vandfartøjer , men det er vigtigt at bemærke, at der stadig er dublerede registreringer af Captain hvor der matcher mange forskellige opslag. Vi sætter dem sammen igen i næste trin.

[ { _id:ObjectId('5f7bea8d79dfe25bf3cb9695'), navn:'CAPTAIN_SAIL', classes:[ 'sail' ], licens:'WC-1', watercraftContexts:{ _id:ObjectId('5f7fea8d6f79cd) , watercraftType:'Sailboat', ref:'sailboats' }, __v:0, vandfartøjer:[ { _id:ObjectId('5f7bea8d79dfe25bf3cb9689'), klasse:'sail', navn:'Borte med vinden', __v:0 } ] }, { _id:ObjectId('5f7bea8d79dfe25bf3cb9696'), navn:'CAPTAIN_YATCH', klasser:[ 'yatch' ], licens:'WC-2', watercraftContexts:{ _id:ObjectId('5f7fea8d8ypec:watercraft:Yatch', ref:'yatches' }, __v:0, vandfartøjer:[ { _id:ObjectId('5f7bea8d79dfe25bf3cb968a'), klasse:'yatch', navn:'Liquid Gold', __v:0 } ] }, { _id:ObjectId('5f7bea8d79dfe25bf3cb9697'), navn:'CAPTAIN_SHIP', klasser:[ 'ship' ], licens:'WC-3', watercraftContexts:{ _id:ObjectId('5f7bea8d79dfe25bf3cb968b') , watercraftType:'Ship', ref:'ships' }, __v:0, watercrafts:[ { _id:ObjectId('5f7bea8d79dfe25bf3cb968b'), class:'ship', name:'Jenny', __v:0 } ] }, { _id:ObjectId('5f7bea8d79dfe25bf3cb969b'), navn:'CAPTAIN_SAIL_YATCH_SHIP', klasser:[ 'sail', 'yatch', 'ship' ], licens:'WC-7', watercraftContexts:{ _id:ObjectId7f7f7fe8bd5b2cf'9b7f7f9b2cf'9b9b9b9b1000 ), watercraftType:'Sailboat', ref:'sailboats' }, __v:0, watercrafts:[ { _id:ObjectId('5f7bea8d79dfe25bf3cb9692'), class:'sail', name:'Swell Shredder', __v:0 } }, { _id:ObjectId('5f7bea8d79dfe25bf3cb969b'), navn:'CAPTAIN_SAIL_YATCH_SHIP', klasser:[ 'sail', 'yatch', 'ship' ], licens:'WC-7', watercraftContexts:{ _id:ObjectId:5f7bea8d79dfe25bf3cb9693'), watercraftType:'Yatch', ref:'yatches' }, __v:0, watercrafts:[ { _id:ObjectId('5f7bea8d79dfe25bf3cb9693'), class:'yatch'' , navn:'Audrey', __v:0 } ] }, { _id:ObjectId('5f7bea8d79dfe25bf3cb969b'), navn:'CAPTAIN_SAIL_YATCH_SHIP', klasser:[ 'sail', 'yatch', 'WC' ], licens:-7', watercraftContexts:{ _id:ObjectId('5f7bea8d79dfe25bf3cb9694'), watercraftType:'Ship', ref:'ships' }, __v:0, watercrafts:[ { _id:ObjectId('5f7fea8d64cship) '5f7fea8d64c ', navn:'Jenny IV', __v:0 } ] } ]

Trin 7 $unwind and $group

Vi $unwind så vi nu kan gruppere alle vandfartøjer tilhørende den samme Captain . Vi skal også bruge $mergeObjects for midlertidigt at gemme de yderligere data fra Captain indsamling under en ny midlertidig variabel for at forberede de sidste faser.

 { '$unwind':'$watercrafts' }, { '$group':{ _id:'$_id', data:{ '$mergeObjects':{ name:'$name', licens:'$license', classes:'$classes', watercraftContexts:'$watercraftContexts', __v:'$__v' } }, vandfartøjer:{ '$push':'$watercrafts' } } } 
$unwind og $group Resultat

Nu er vi virkelig på vej et sted hen. Vi har reduceret vores transformation til vores oprindelige 4 Captain s og fladede vores joins til et enkelt array.

[ { _id:ObjectId('5f7bed5e271dd95c306c25a4'), data:{ name:'CAPTAIN_SHIP', licens:'WC-3', classes:[ 'ship' ], watercraftContexts:{ _id:ObjectId(' 5f7bed5e271dd95c306c2598'), watercraftType:'Ship', ref:'ships' }, __v:0 }, vandfartøjer:[ { _id:ObjectId('5f7bed5e271dd95c306c2598'), klasse:'Jenny', ', class:'Jenny', ',' } ] }, { _id:ObjectId('5f7bed5e271dd95c306c25a8'), data:{ navn:'CAPTAIN_SAIL_YATCH_SHIP', licens:'WC-7', klasser:[ 'sail', 'yatch', 'ship' ], watercraftContexts:{ _id:ObjectId('5f7bed5e271dd95c306c25a1'), watercraftType:'Ship', ref:'ships' }, __v:0 }, vandfartøjer:[ { _id:ObjectId('5f7bed5e271dd95c306c259sfail'), class:'Sfail', class:'Sfail' Shredder', __v:0 }, { _id:ObjectId('5f7bed5e271dd95c306c25a0'), klasse:'yatch', navn:'Audrey', __v:0 } , { _id:ObjectId('5f7bed5e271dd95c306c25a1'), klasse:'ship', name:'Jenny IV', __v:0 } ] }, { _id:ObjectId('5f7bed5e271dd95c306c25a2 'CA:'), data licens:'WC-1', klasser:[ 'sail' ], watercraftContexts:{ _id:Object('5f7bed5e271dd95c306c2596'), watercraftType:'Sailboat', ref:'sailboats' }, __v:0 }, vandfartøjer:[ { _id:ObjectId('5f7bed5e271dd95c306c2596'), klasse:'sail', navn:'Borte med vinden', __v:0 } ] }, { _id:ObjectId('5f7bed5e271dd95c306c25_Y name:AT:CA:KH:'), data licens:'WC-2', klasser:[ 'yatch' ], watercraftContexts:{ _id:ObjectId('5f7bed5e271dd95c306c2597'), watercraftType:'Yatch', ref:'yatches' }, __v:0 }, vandfartøjer:[ { _id:ObjectId('5f7bed5e271dd95c306c2597'), klasse:'yatch', navn:'Liquid Gold', __v:0 } ] } ] 

Trin 8 $replaceRoot og $project

Det eneste, vi har tilbage, er at flette vores data ind i roden af ​​hver post og fjern den midlertidige variabel data

 // Fletter 'data' ind i roden af ​​hver post { '$replaceRoot':{ newRoot:{ '$mergeObjects':[ '$data', '$$ROOT' ] } } }, / / Brug $project til at fjerne data (inkluder kun de felter, vi ønsker) { '$project':{ name:true, license:true, classes:true, _id:true, watercraftContexts:true, __v:true, watercrafts:true } } 
$replaceRoot &$project Resultat

Nu har vi det resultat, vi satte os for...En Captain med en række blandede tilknyttede typer vandfartøjer

[ { navn:'CAPTAIN_SAIL_YATCH_SHIP', licens:'WC-7', klasser:[ 'sail', 'yatch', 'ship' ], watercraftContexts:{ _id:ObjectId('5f7bf3b3680b375ca1755ea6'), watercraftType:'Ship', ref:'ships' }, __v:0, _id:ObjectId('5f7bf3b3680b375ca1755ead'), vandfartøjer:[ { _id:ObjectId('5f7bf3b3680b375asail'), class:Shred 'Swell', class:Shred 'Swell' ', __v:0 }, { _id:ObjectId('5f7bf3b3680b375ca1755ea5'), klasse:'yatch', navn:'Audrey', __v:0 }, { _id:ObjectId('5f7bf3b36177b555caship, class 'eacaship,' navn:'Jenny IV', __v:0 } ] }, { navn:'CAPTAIN_SAIL', licens:'WC-1', klasser:[ 'sail' ], watercraftContexts:{ _id:ObjectId('5f7bf3b3680b375ca1755e9b'), vandfartøjer :'Sejlbåd', ref:'sejlbåde' }, __v:0, _id:ObjectId('5f7bf3b3680b375ca1755ea7'), vandfartøjer:[ { _id:ObjectId('5f7bf3b3680b375ca175e'), klasse:'sail', navn:'Borte med vinden', __v:0 } ] }, { navn:'CAPTAIN_YATCH', licens:'WC-2', klasser:[ 'yatch' ], vandfartøjContexts:{ _id:ObjectId('5f7bf3b3680b375ca1755e9c'), watercraftType:'Yatch', ref:'yatches' }, __v:0, _id:ObjectId('5f7bf3b3680b375ca1755ea8'), _(31cid:5bd:class:57b:5b,7b,5f7bf3b3680b375ca1755ea8') ', navn:'Liquid Gold', __v:0 } ] }, { name:'CAPTAIN_SHIP', licens:'WC-3', classes:[ 'ship' ], watercraftContexts:{ _id:ObjectId('5f7bf3b3680b375ca1755e9d') , watercraftType:'Ship', ref:'ships' }, __v:0, _id:ObjectId('5f7bf3b3680b375ca1755ea9'), vandfartøjer:[ { _id:ObjectId('5f7bf3b3680b3680b35e9cad,eny, class:'Jen917'en'en'), ', __v:0 } ] } ] 

Og der har du det... tog kun 2 dage at finde ud af det. Jeg håber, det sparer dig noget tid, hvis du prøver en lignende samlet tilknytning. God kodning!

Endelig rørledning

  [{'$ match':{_id:{'$ in':[objectId ('5f7bf3b3680b375ca1755ea9'), objectId ('5f7bf3b3680b375ca1755ea7'), objekt ('5f7bf3b3680b375ca175550505)) ] } } }, { '$unwind':'$watercraftContexts' }, { '$lookup':{ from:'ships', localField:'watercraftContexts._id', foreignField:'_id', as:'watercrafts.ships ' } }, { '$unwind':'$watercraftContexts' }, { '$lookup':{ from:'yatches', localField:'watercraftContexts._id', foreignField:'_id', as:'watercrafts.yatches' } }, { '$unwind':'$watercraftContexts' }, { '$lookup':{ from:'sailboats', localField:'watercraftContexts._id', foreignField:'_id', as:'watercrafts.sailboats' } }, { '$project':{ name:true, licens:true, classes:true, _id:true, watercraftContexts:true, __v:true, watercrafts:{ '$setUnion':[ '$watercrafts.ships', '$watercrafts.yatches', '$watercrafts.sailboats' ] } } }, { '$unwind':'$watercrafts' }, { '$group':{ _id:'$_id', data:{ '$mergeObjects':{ name:'$name', licens:'$license', classes:'$classes', watercraftContexts:'$watercraftContexts', __v:'$__v ' } }, vandfartøjer:{ '$push':'$vandfartøjer' } } }, { '$replaceRoot':{ newRoot:{ '$mergeObjects':[ '$data', '$$ROOT' ] } } , { '$project':{ name:true, license:true, classes:true, _id:true, watercraftContexts:true, __v:true, watercrafts:true } }] 



  1. findOne virker, men får ikke alle/find

  2. Redis masseindsættelse

  3. MongoDB PHP:Hvordan får jeg ObjectId med et JSON-feed? (det er tomt)

  4. MongooseJS/MongoDB søge nøjagtig sætning