Come eseguo l'equivalente SQL Join in MongoDB?


498

Come eseguo l'equivalente SQL Join in MongoDB?

Ad esempio, supponiamo che tu abbia due raccolte (utenti e commenti) e voglio estrarre tutti i commenti con pid = 444 insieme alle informazioni dell'utente per ciascuno.

comments
  { uid:12345, pid:444, comment="blah" }
  { uid:12345, pid:888, comment="asdf" }
  { uid:99999, pid:444, comment="qwer" }

users
  { uid:12345, name:"john" }
  { uid:99999, name:"mia"  }

C'è un modo per estrarre tutti i commenti con un determinato campo (es. ... find ({pid: 444})) e le informazioni utente associate a ciascun commento in una volta sola?

Al momento, ricevo prima i commenti che corrispondono ai miei criteri, quindi capisco tutti gli uid in quel set di risultati, ottengo gli oggetti utente e li unisco ai risultati del commento. Sembra che lo stia facendo male.


35
L'ultima risposta a questa domanda è probabilmente la più pertinente, poiché MongoDB 3.2+ ha implementato una soluzione di join chiamata $ lookup. Ho pensato di spingerlo qui perché forse non tutti leggeranno in fondo. stackoverflow.com/a/33511166/2593330
thefourtheye

6
Corretto, $ lookup è stato introdotto in MongoDB 3.2. I dettagli sono disponibili su docs.mongodb.org/master/reference/operator/aggregation/lookup/…
NDB

Risposte:


306

A partire da Mongo 3.2 le risposte a questa domanda per lo più non sono più corrette. Il nuovo operatore $ lookup aggiunto alla pipeline di aggregazione è essenzialmente identico a un join esterno sinistro:

https://docs.mongodb.org/master/reference/operator/aggregation/lookup/#pipe._S_lookup

Dai documenti:

{
   $lookup:
     {
       from: <collection to join>,
       localField: <field from the input documents>,
       foreignField: <field from the documents of the "from" collection>,
       as: <output array field>
     }
}

Ovviamente Mongo non è un database relazionale, e gli sviluppatori stanno facendo attenzione a raccomandare casi d'uso specifici per $ lookup, ma almeno a partire da 3.2 fare join è ora possibile con MongoDB.


@clayton: che ne dici di più di due collezioni?
Dipen Dedania,

1
@DipenDedania ha appena aggiunto ulteriori $ $ di ricerca alla pipeline di aggregazione.
Clayton Gulick il

Non posso unirmi a nessun campo nella matrice nella raccolta a sinistra con il suo id corrispondente nella raccolta a destra. Qualcuno mi può aiutare ??
Prateek Singh,

1
Sono un po 'confuso su questo - c'è un modo per specificare che vuoi solo determinati documenti nella raccolta "from", o si unisce automaticamente tutti in db contemporaneamente?
user3413723,

Ti stai solo chiedendo se l'ultimo Spring Data MongoDB ha il supporto per 3.2?
gtiwari333,

142

Questa pagina sul sito ufficiale di mongodb risponde esattamente a questa domanda:

https://mongodb-documentation.readthedocs.io/en/latest/ecosystem/tutorial/model-data-for-ruby-on-rails.html

Quando visualizziamo il nostro elenco di storie, dovremo mostrare il nome dell'utente che ha pubblicato la storia. Se stessimo utilizzando un database relazionale, potremmo eseguire un join su utenti e negozi e ottenere tutti i nostri oggetti in un'unica query. Ma MongoDB non supporta i join e quindi, a volte, richiede un po 'di denormalizzazione. Qui, questo significa memorizzare nella cache l'attributo 'username'.

I puristi relazionali potrebbero già sentirsi a disagio, come se stessimo violando una legge universale. Ma ricordiamo che le raccolte MongoDB non sono equivalenti alle tabelle relazionali; ognuno ha un obiettivo di design unico. Una tabella normalizzata fornisce una porzione atomica e isolata di dati. Un documento, tuttavia, rappresenta più da vicino un oggetto nel suo insieme. Nel caso di un sito di notizie sociali, si può sostenere che un nome utente è intrinseco alla storia pubblicata.


51
@dudelgrincen è un passaggio di paradigma dalla normalizzazione ai database relazionali. L'obiettivo di un NoSQL è leggere e scrivere dal database molto rapidamente. Con BigData avrai molti applicativi e server front-end con numeri più bassi sui DB. Dovresti fare milioni di transazioni al secondo. Scaricare il sollevamento pesante dal database e metterlo a livello di applicazione. Se è necessaria un'analisi approfondita, si esegue un processo di integrazione che inserisce i dati in un database OLAP. Non dovresti comunque ricevere molte domande approfondite dal tuo dbs OLTP.
Bruciato dalla neve il

18
@dudelgrincen Dovrei anche dire che non è per ogni progetto o design. Se hai qualcosa che funziona in un database di tipo SQL, perché cambiarlo? Se non riesci a massaggiare il tuo schema per lavorare con noSQL, allora non farlo.
Bruciato dalla neve il

9
Le migrazioni e gli schemi in costante evoluzione sono anche molto più facili da gestire su un sistema NoSQL.
Giusto

14
Cosa succede se l'utente ha 3.540 post nel sito Web e cambia il suo nome utente nel profilo? Ogni post deve essere aggiornato con il nuovo nome utente?
Ivo Pereira,

2
@IvoPereira Sì ed è esattamente per questo che si dovrebbe evitare di modellare i dati in questo modo. C'è un articolo che spiega lo stesso scenario e le sue conseguenze: Perché non dovresti mai usare MongoDB
Omid

138

Possiamo unire / unire tutti i dati all'interno di una sola raccolta con una semplice funzione in poche righe usando la console client mongodb e ora potremmo essere in grado di eseguire la query desiderata. Di seguito un esempio completo,

.- Autori:

db.authors.insert([
    {
        _id: 'a1',
        name: { first: 'orlando', last: 'becerra' },
        age: 27
    },
    {
        _id: 'a2',
        name: { first: 'mayra', last: 'sanchez' },
        age: 21
    }
]);

.- Categorie:

db.categories.insert([
    {
        _id: 'c1',
        name: 'sci-fi'
    },
    {
        _id: 'c2',
        name: 'romance'
    }
]);

.- Libri

db.books.insert([
    {
        _id: 'b1',
        name: 'Groovy Book',
        category: 'c1',
        authors: ['a1']
    },
    {
        _id: 'b2',
        name: 'Java Book',
        category: 'c2',
        authors: ['a1','a2']
    },
]);

.- Prestito di libri

db.lendings.insert([
    {
        _id: 'l1',
        book: 'b1',
        date: new Date('01/01/11'),
        lendingBy: 'jose'
    },
    {
        _id: 'l2',
        book: 'b1',
        date: new Date('02/02/12'),
        lendingBy: 'maria'
    }
]);

.- La magia:

db.books.find().forEach(
    function (newBook) {
        newBook.category = db.categories.findOne( { "_id": newBook.category } );
        newBook.lendings = db.lendings.find( { "book": newBook._id  } ).toArray();
        newBook.authors = db.authors.find( { "_id": { $in: newBook.authors }  } ).toArray();
        db.booksReloaded.insert(newBook);
    }
);

.- Ottieni i nuovi dati di raccolta:

db.booksReloaded.find().pretty()

.- Risposta :)

{
    "_id" : "b1",
    "name" : "Groovy Book",
    "category" : {
        "_id" : "c1",
        "name" : "sci-fi"
    },
    "authors" : [
        {
            "_id" : "a1",
            "name" : {
                "first" : "orlando",
                "last" : "becerra"
            },
            "age" : 27
        }
    ],
    "lendings" : [
        {
            "_id" : "l1",
            "book" : "b1",
            "date" : ISODate("2011-01-01T00:00:00Z"),
            "lendingBy" : "jose"
        },
        {
            "_id" : "l2",
            "book" : "b1",
            "date" : ISODate("2012-02-02T00:00:00Z"),
            "lendingBy" : "maria"
        }
    ]
}
{
    "_id" : "b2",
    "name" : "Java Book",
    "category" : {
        "_id" : "c2",
        "name" : "romance"
    },
    "authors" : [
        {
            "_id" : "a1",
            "name" : {
                "first" : "orlando",
                "last" : "becerra"
            },
            "age" : 27
        },
        {
            "_id" : "a2",
            "name" : {
                "first" : "mayra",
                "last" : "sanchez"
            },
            "age" : 21
        }
    ],
    "lendings" : [ ]
}

Spero che queste righe possano aiutarti.


2
mi chiedo se questo stesso codice possa essere eseguito usando dottrine mongodb?
circa

4
Cosa succede quando uno degli oggetti di riferimento riceve un aggiornamento? Tale aggiornamento si riflette automaticamente nell'oggetto libro? O quel loop deve essere eseguito di nuovo?
Balupton,

14
Questo va bene finché i tuoi dati sono piccoli. Porterà i contenuti di ogni libro al tuo cliente e poi recupererà ogni categoria, prestito e autori uno per uno. Nel momento in cui i tuoi libri sono in migliaia, questo andrebbe davvero molto lentamente. Una tecnica migliore sarebbe probabilmente quella di utilizzare la pipeline di aggregazione e produrre i dati uniti in una raccolta separata. Fammi tornare di nuovo. Aggiungerò una risposta.
Sandeep Giri,

Puoi adattare il tuo algoritmo a questo altro esempio? stackoverflow.com/q/32718079/287948
Peter Krauss,

1
@SandeepGiri come posso fare la pipeline aggregata dal momento che ho dati davvero molto intensi nella raccolta separata devo unirmi ??
Yassine Abdul-Rahman,

38

Devi farlo come hai descritto. MongoDB è un database non relazionale e non supporta i join.


4
Sembra che le prestazioni sbagliate vengano dal background di un server SQL, ma forse non è così male con un documento db?
terjetyl,

3
anche da un server SQL, apprezzerei MongoDB che prende un 'set di risultati' (con campi restituiti selezionati) come input per una nuova query in una volta, proprio come le query nidificate in SQL
Stijn Sanders,

1
@terjetyl Devi davvero pianificarlo. Quali campi presenterai nel front-end, se è un importo limitato in una vista individuale, li prendi come documenti incorporati. La chiave è non dover fare join. Se vuoi fare un'analisi approfondita, lo fai dopo il fatto in un altro database. Esegui un lavoro che trasforma i dati in un cubo OLAP per prestazioni ottimali.
Bruciato dalla neve il

4
Dalla versione 3.2 di mongo sono supportati i join di sinistra.
Somnath Muluk,

18

Come altri hanno sottolineato, stai provando a creare un database relazionale da nessun database relazionale che in realtà non vuoi fare ma comunque, se hai un caso in cui devi farlo qui è una soluzione che puoi usare. Facciamo prima una ricerca foreach sulla raccolta A (o nel tuo caso gli utenti) e poi otteniamo ogni articolo come oggetto quindi usiamo la proprietà dell'oggetto (nel tuo caso uid) per cercare nella nostra seconda raccolta (nei commenti del tuo caso) se noi possiamo trovarlo, quindi abbiamo una corrispondenza e possiamo stampare o fare qualcosa con esso. Spero che questo ti aiuti e buona fortuna :)

db.users.find().forEach(
function (object) {
    var commonInBoth=db.comments.findOne({ "uid": object.uid} );
    if (commonInBoth != null) {
        printjson(commonInBoth) ;
        printjson(object) ;
    }else {
        // did not match so we don't care in this case
    }
});

Non trovi questo articolo su cui stiamo attualmente eseguendo il loop?
Skarlinski,

18

Con la giusta combinazione di $ lookup , $ project e $ match , puoi unire più tabelle su più parametri. Questo perché possono essere concatenati più volte.

Supponiamo di voler fare quanto segue ( riferimento )

SELECT S.* FROM LeftTable S
LEFT JOIN RightTable R ON S.ID =R.ID AND S.MID =R.MID WHERE R.TIM >0 AND 
S.MOB IS NOT NULL

Passaggio 1: collega tutte le tabelle

puoi $ cercare tutte le tabelle che vuoi.

$ lookup - uno per ogni tabella nella query

$ unwind - perché i dati sono denormalizzati correttamente, altrimenti inseriti in array

Codice Python ..

db.LeftTable.aggregate([
                        # connect all tables

                        {"$lookup": {
                          "from": "RightTable",
                          "localField": "ID",
                          "foreignField": "ID",
                          "as": "R"
                        }},
                        {"$unwind": "R"}

                        ])

Passaggio 2: definire tutti i condizionali

$ project : qui definisci tutte le istruzioni condizionali, più tutte le variabili che desideri selezionare.

Codice Python ..

db.LeftTable.aggregate([
                        # connect all tables

                        {"$lookup": {
                          "from": "RightTable",
                          "localField": "ID",
                          "foreignField": "ID",
                          "as": "R"
                        }},
                        {"$unwind": "R"},

                        # define conditionals + variables

                        {"$project": {
                          "midEq": {"$eq": ["$MID", "$R.MID"]},
                          "ID": 1, "MOB": 1, "MID": 1
                        }}
                        ])

Passaggio 3: unisciti a tutti i condizionali

$ match - unisciti a tutte le condizioni usando OR o AND ecc. Possono esserci multipli di questi.

$ project : annulla la definizione di tutti i condizionali

Codice Python ..

db.LeftTable.aggregate([
                        # connect all tables

                        {"$lookup": {
                          "from": "RightTable",
                          "localField": "ID",
                          "foreignField": "ID",
                          "as": "R"
                        }},
                        {"$unwind": "$R"},

                        # define conditionals + variables

                        {"$project": {
                          "midEq": {"$eq": ["$MID", "$R.MID"]},
                          "ID": 1, "MOB": 1, "MID": 1
                        }},

                        # join all conditionals

                        {"$match": {
                          "$and": [
                            {"R.TIM": {"$gt": 0}}, 
                            {"MOB": {"$exists": True}},
                            {"midEq": {"$eq": True}}
                        ]}},

                        # undefine conditionals

                        {"$project": {
                          "midEq": 0
                        }}

                        ])

Praticamente qualsiasi combinazione di tabelle, condizionali e join può essere eseguita in questo modo.


17

Ecco un esempio di un "join" * Collezioni di attori e film :

https://github.com/mongodb/cookbook/blob/master/content/patterns/pivot.txt

Fa uso del .mapReduce()metodo

* join - un'alternativa per unirsi in database orientati ai documenti


19
-1, questo NON unisce i dati di due raccolte. Sta usando i dati di una singola raccolta (attori) che ruota attorno ai dati. In modo che le cose che erano chiavi ora sono valori e valori ora sono chiavi ... molto diversi da un JOIN.
Evan Teran,

12
Questo è esattamente ciò che devi fare, MongoDB non è relazionale ma orientato ai documenti. MapReduce consente di giocare con dati con grandi prestazioni (è possibile utilizzare cluster ecc ....) ma anche per casi semplici, è molto utile!
Thomas Decaux,

14

Puoi unire due raccolte in Mongo usando la ricerca che è disponibile nella versione 3.2. Nel tuo caso la query sarebbe

db.comments.aggregate({
    $lookup:{
        from:"users",
        localField:"uid",
        foreignField:"uid",
        as:"users_comments"
    }
})

oppure puoi anche unirti rispetto agli utenti, quindi ci sarà un piccolo cambiamento come indicato di seguito.

db.users.aggregate({
    $lookup:{
        from:"comments",
        localField:"uid",
        foreignField:"uid",
        as:"users_comments"
    }
})

Funzionerà esattamente come il join destro e sinistro in SQL.


11

Dipende da cosa stai cercando di fare.

Attualmente lo hai impostato come un database normalizzato, il che va bene e il modo in cui lo stai facendo è appropriato.

Tuttavia, ci sono altri modi per farlo.

È possibile disporre di una raccolta di post con commenti incorporati per ogni post con riferimenti agli utenti che è possibile richiedere in modo iterativo per ottenere. È possibile memorizzare il nome dell'utente con i commenti, è possibile memorizzarli tutti in un unico documento.

La cosa con NoSQL è che è progettato per schemi flessibili e lettura e scrittura molto veloci. In una tipica fattoria Big Data il database è il maggiore collo di bottiglia, hai meno motori di database rispetto ai server di applicazioni e front-end ... sono più costosi ma più potenti, anche lo spazio sul disco rigido è relativamente economico. La normalizzazione deriva dal concetto di cercare di risparmiare spazio, ma comporta un costo per rendere i database eseguire join complicati e verificare l'integrità delle relazioni, eseguendo operazioni a cascata. Tutto ciò fa risparmiare agli sviluppatori mal di testa se hanno progettato correttamente il database.

Con NoSQL, se si accetta che la ridondanza e lo spazio di archiviazione non sono problemi a causa del loro costo (sia nel tempo del processore necessario per eseguire aggiornamenti sia nei costi del disco rigido per archiviare dati extra), la denormalizzazione non è un problema (per gli array incorporati che diventano centinaia di migliaia di articoli può essere un problema di prestazioni, ma il più delle volte non è un problema). Inoltre avrai diversi server di applicazioni e front-end per ogni cluster di database. Invitali a sollevare pesantemente i join e a consentire ai server di database di leggere e scrivere.

TL; DR: Quello che stai facendo va bene, e ci sono altri modi per farlo. Dai un'occhiata ai modelli del modello di dati della documentazione di mongodb per alcuni grandi esempi. http://docs.mongodb.org/manual/data-modeling/


8
"La normalizzazione deriva dal concetto di cercare di risparmiare spazio", lo metto in dubbio. La normalizzazione IMHO deriva dal concetto di evitare la ridondanza. Supponi di memorizzare il nome di un utente insieme a un post sul blog. E se si sposa? In un modello non normalizzato dovrai passare in rassegna tutti i post e cambiare il nome. In un modello normalizzato di solito si modifica UN record.
DanielKhan,

@DanielKhan la prevenzione della ridondanza e il risparmio di spazio sono concetti simili, ma sulla nuova analisi sono d'accordo, la ridondanza è la causa principale di questo progetto. Ti riformulo. Grazie per la nota.
Bruciato dalla neve il

11

C'è una specifica che molti driver supportano che si chiama DBRef.

DBRef è una specifica più formale per la creazione di riferimenti tra documenti. I DBRef (generalmente) includono un nome di raccolta e un ID oggetto. La maggior parte degli sviluppatori utilizza DBRefs solo se la raccolta può passare da un documento al successivo. Se la tua raccolta referenziata sarà sempre la stessa, i riferimenti manuali descritti sopra sono più efficienti.

Tratto da Documentazione MongoDB: Modelli di dati> Riferimento del modello di dati> Riferimenti al database


11

$ lookup (aggregazione)

Esegue un join esterno sinistro a una raccolta non frammentata nello stesso database per filtrare i documenti della raccolta "unita" per l'elaborazione. Ad ogni documento di input, la fase $ lookup aggiunge un nuovo campo di matrice i cui elementi sono i documenti corrispondenti della raccolta "unita". La fase $ lookup passa questi documenti rimodellati alla fase successiva. La fase $ lookup ha le seguenti sintassi:

Partita di uguaglianza

Per eseguire una corrispondenza di uguaglianza tra un campo dai documenti di input e un campo dai documenti della raccolta "unita", la fase $ lookup ha la sintassi seguente:

{
   $lookup:
     {
       from: <collection to join>,
       localField: <field from the input documents>,
       foreignField: <field from the documents of the "from" collection>,
       as: <output array field>
     }
}

L'operazione corrisponderebbe alla seguente istruzione pseudo-SQL:

SELECT *, <output array field>
FROM collection
WHERE <output array field> IN (SELECT <documents as determined from the pipeline>
                               FROM <collection to join>
                               WHERE <pipeline> );

Mongo URL


la query secondaria è totalmente diversa da join, se la tabella di sinistra è enorme, la query secondaria indica che ogni riga deve eseguire una query da sola. diventerà molto lento. join è molto veloce in sql.
yww325

8

Prima della 3.2.6 , Mongodb non supporta la query di join come mysql. sotto la soluzione che funziona per te.

 db.getCollection('comments').aggregate([
        {$match : {pid : 444}},
        {$lookup: {from: "users",localField: "uid",foreignField: "uid",as: "userData"}},
   ])


3

MongoDB non consente i join, ma è possibile utilizzare plug-in per gestirlo. Controlla il plugin mongo-join. È il migliore e l'ho già usato. Puoi installarlo usando npm direttamente in questo modo npm install mongo-join. Puoi consultare la documentazione completa con esempi .

(++) strumento davvero utile quando dobbiamo unire le raccolte (N)

(-) possiamo applicare condizioni solo al livello più alto della query

Esempio

var Join = require('mongo-join').Join, mongodb = require('mongodb'), Db = mongodb.Db, Server = mongodb.Server;
db.open(function (err, Database) {
    Database.collection('Appoint', function (err, Appoints) {

        /* we can put conditions just on the top level */
        Appoints.find({_id_Doctor: id_doctor ,full_date :{ $gte: start_date },
            full_date :{ $lte: end_date }}, function (err, cursor) {
            var join = new Join(Database).on({
                field: '_id_Doctor', // <- field in Appoints document
                to: '_id',         // <- field in User doc. treated as ObjectID automatically.
                from: 'User'  // <- collection name for User doc
            }).on({
                field: '_id_Patient', // <- field in Appoints doc
                to: '_id',         // <- field in User doc. treated as ObjectID automatically.
                from: 'User'  // <- collection name for User doc
            })
            join.toArray(cursor, function (err, joinedDocs) {

                /* do what ever you want here */
                /* you can fetch the table and apply your own conditions */
                .....
                .....
                .....


                resp.status(200);
                resp.json({
                    "status": 200,
                    "message": "success",
                    "Appoints_Range": joinedDocs,


                });
                return resp;


            });

    });

2

Puoi farlo utilizzando la pipeline di aggregazione, ma è una seccatura scriverlo da solo.

È possibile utilizzare mongo-join-queryper creare automaticamente la pipeline di aggregazione dalla query.

Ecco come apparirebbe la tua query:

const mongoose = require("mongoose");
const joinQuery = require("mongo-join-query");

joinQuery(
    mongoose.models.Comment,
    {
        find: { pid:444 },
        populate: ["uid"]
    },
    (err, res) => (err ? console.log("Error:", err) : console.log("Success:", res.results))
);

Il tuo risultato avrebbe l'oggetto utente nel uidcampo e puoi collegare tutti i livelli che vuoi. È possibile popolare il riferimento all'utente, che fa riferimento a una squadra, che fa riferimento a qualcos'altro, ecc.

Disclaimer : ho scritto mongo-join-queryper affrontare questo esatto problema.


0

playORM può farlo per te usando S-SQL (SQL scalabile) che aggiunge semplicemente il partizionamento in modo da poter fare join all'interno delle partizioni.


-2

No, non sembra che tu stia sbagliando. I join MongoDB sono "lato client". Più o meno come hai detto:

Al momento, ricevo prima i commenti che corrispondono ai miei criteri, quindi capisco tutti gli uid in quel set di risultati, ottengo gli oggetti utente e li unisco ai risultati del commento. Sembra che lo stia facendo male.

1) Select from the collection you're interested in.
2) From that collection pull out ID's you need
3) Select from other collections
4) Decorate your original results.

Non è un join "reale", ma in realtà è molto più utile di un join SQL perché non è necessario gestire righe duplicate per "molti" join laterali, invece decorare il set originariamente selezionato.

Ci sono molte sciocchezze e FUD in questa pagina. 5 anni dopo MongoDB è ancora una cosa.


'non devi avere a che fare con righe duplicate per "molti" join laterali " - non hai idea di cosa intendi con questo. Puoi chiarire?
Mark Amery,

1
@MarkAmery, certo. In SQL una relazione nn restituirà righe duplicate. Ad esempio amici. Se Bob è amico di Mary e Jane, otterrai 2 file per Bob: Bob, Mary e Bob, Jane. 2 Bobs è una bugia, c'è solo un Bob. Con i join lato client puoi iniziare con Bob e decorare come preferisci: Bob, "Mary and Jane". SQL ti consente di farlo con le subquery, ma ciò sta facendo un lavoro sul server db che potrebbe essere fatto sul client.
Michael Cole,

-3

Penso che, se hai bisogno di tabelle di dati normalizzate, devi provare alcune altre soluzioni di database.

Ma ho messo a tacere quel sollution per MOngo su Git A proposito, nel codice degli inserti: ha il nome del film, ma l'ID del film .

Problema

Hai una collezione di attori con una serie di film che hanno fatto.

Vuoi generare una raccolta di film con una serie di attori in ciascuno.

Alcuni dati di esempio

 db.actors.insert( { actor: "Richard Gere", movies: ['Pretty Woman', 'Runaway Bride', 'Chicago'] });
 db.actors.insert( { actor: "Julia Roberts", movies: ['Pretty Woman', 'Runaway Bride', 'Erin Brockovich'] });

Soluzione

Dobbiamo passare in rassegna ogni film nel documento Attore ed emettere ogni film singolarmente.

Il problema qui è nella fase di riduzione. Non è possibile emettere un array dalla fase di riduzione, quindi è necessario creare un array Actors all'interno del documento "value" che viene restituito.

Il codice
map = function() {
  for(var i in this.movies){
    key = { movie: this.movies[i] };
    value = { actors: [ this.actor ] };
    emit(key, value);
  }
}

reduce = function(key, values) {
  actor_list = { actors: [] };
  for(var i in values) {
    actor_list.actors = values[i].actors.concat(actor_list.actors);
  }
  return actor_list;
}

Notare come la lista_attore è in realtà un oggetto JavaScript che contiene un array. Si noti inoltre che la mappa emette la stessa struttura.

Eseguire quanto segue per eseguire la mappa / riduzione, inviarlo alla raccolta "pivot" e stampare il risultato:

printjson (db.actors.mapReduce (mappa, ridurre, "pivot")); db.pivot.find () foreach (printjson).;

Ecco l'output di esempio, notare che "Pretty Woman" e "Runaway Bride" hanno sia "Richard Gere" che "Julia Roberts".

{ "_id" : { "movie" : "Chicago" }, "value" : { "actors" : [ "Richard Gere" ] } }
{ "_id" : { "movie" : "Erin Brockovich" }, "value" : { "actors" : [ "Julia Roberts" ] } }
{ "_id" : { "movie" : "Pretty Woman" }, "value" : { "actors" : [ "Richard Gere", "Julia Roberts" ] } }
{ "_id" : { "movie" : "Runaway Bride" }, "value" : { "actors" : [ "Richard Gere", "Julia Roberts" ] } }


Nota che la maggior parte del contenuto di questa risposta (cioè il bit che è in inglese comprensibile) è copiato dal ricettario MongoDB sul link GitHub fornito dal risponditore.
Mark Amery,

-4

È possibile unire due raccolte utilizzando la query secondaria mongoDB. Ecco un esempio, Commenti:

`db.commentss.insert([
  { uid:12345, pid:444, comment:"blah" },
  { uid:12345, pid:888, comment:"asdf" },
  { uid:99999, pid:444, comment:"qwer" }])`

Userss--

db.userss.insert([
  { uid:12345, name:"john" },
  { uid:99999, name:"mia"  }])

Sottoquery MongoDB per JOIN--

`db.commentss.find().forEach(
    function (newComments) {
        newComments.userss = db.userss.find( { "uid": newComments.uid } ).toArray();
        db.newCommentUsers.insert(newComments);
    }
);`

Ottieni risultati dalla raccolta appena generata:

db.newCommentUsers.find().pretty()

Risultato--

`{
    "_id" : ObjectId("5511236e29709afa03f226ef"),
    "uid" : 12345,
    "pid" : 444,
    "comment" : "blah",
    "userss" : [
        {
            "_id" : ObjectId("5511238129709afa03f226f2"),
            "uid" : 12345,
            "name" : "john"
        }
    ]
}
{
    "_id" : ObjectId("5511236e29709afa03f226f0"),
    "uid" : 12345,
    "pid" : 888,
    "comment" : "asdf",
    "userss" : [
        {
            "_id" : ObjectId("5511238129709afa03f226f2"),
            "uid" : 12345,
            "name" : "john"
        }
    ]
}
{
    "_id" : ObjectId("5511236e29709afa03f226f1"),
    "uid" : 99999,
    "pid" : 444,
    "comment" : "qwer",
    "userss" : [
        {
            "_id" : ObjectId("5511238129709afa03f226f3"),
            "uid" : 99999,
            "name" : "mia"
        }
    ]
}`

Spero che questo possa aiutare.


7
Perché hai praticamente copiato questa risposta di un anno quasi identica? stackoverflow.com/a/22739813/4186945
Hackel
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.