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

Come scrivere query di unione in mongoDB

È possibile eseguire unioni in MongoDB in modo "SQL UNION" utilizzando le aggregazioni insieme alle ricerche, in un'unica query.

Qualcosa del genere:

    db.getCollection("AnyCollectionThatContainsAtLeastOneDocument").aggregate(
    [
      { $limit: 1 }, // Reduce the result set to a single document.
      { $project: { _id: 1 } }, // Strip all fields except the Id.
      { $project: { _id: 0 } }, // Strip the id. The document is now empty.

      // Lookup all collections to union together.
      { $lookup: { from: 'collectionToUnion1', pipeline: [...], as: 'Collection1' } },
      { $lookup: { from: 'collectionToUnion2', pipeline: [...], as: 'Collection2' } },
      { $lookup: { from: 'collectionToUnion3', pipeline: [...], as: 'Collection3' } },

      // Merge the collections together.
      {
        $project:
        {
          Union: { $concatArrays: ["$Collection1", "$Collection2", "$Collection3"] }
        }
      },

      { $unwind: "$Union" }, // Unwind the union collection into a result set.
      { $replaceRoot: { newRoot: "$Union" } } // Replace the root to cleanup the resulting documents.
    ]);

Ecco la spiegazione di come funziona:

  1. Crea un'istanza di un aggregate su qualsiasi raccolta del tuo database che contiene almeno un documento. Se non puoi garantire che qualsiasi raccolta del tuo database non sarà vuota, puoi aggirare questo problema creando nel tuo database una sorta di raccolta "fittizia" contenente un singolo documento vuoto che sarà lì specificamente per eseguire query di unione.

  2. Fai in modo che la prima fase della tua pipeline sia { $limit: 1 } . Questo eliminerà tutti i documenti della collezione tranne il primo.

  3. Elimina tutti i campi del documento rimanente utilizzando $project fasi:

    { $project: { _id: 1 } },
    { $project: { _id: 0 } }
    
  4. Il tuo aggregato ora contiene un unico documento vuoto. È ora di aggiungere ricerche per ogni raccolta che desideri unire. Puoi usare la pipeline campo per eseguire un filtro specifico o lasciare localField e foreignField come null per corrispondere all'intera collezione.

    { $lookup: { from: 'collectionToUnion1', pipeline: [...], as: 'Collection1' } },
    { $lookup: { from: 'collectionToUnion2', pipeline: [...], as: 'Collection2' } },
    { $lookup: { from: 'collectionToUnion3', pipeline: [...], as: 'Collection3' } }
    
  5. Ora hai un aggregato contenente un singolo documento che contiene 3 array come questo:

    {
        Collection1: [...],
        Collection2: [...],
        Collection3: [...]
    }
    

    Puoi quindi unirli insieme in un unico array usando un $project stage insieme a $concatArrays operatore di aggregazione:

    {
      "$project" :
      {
        "Union" : { $concatArrays: ["$Collection1", "$Collection2", "$Collection3"] }
      }
    }
    
  6. Ora hai un aggregato contenente un singolo documento, in cui si trova un array che contiene la tua unione di raccolte. Quello che resta da fare è aggiungere un $unwind e un $replaceRoot stage per dividere l'array in documenti separati:

    { $unwind: "$Union" },
    { $replaceRoot: { newRoot: "$Union" } }
    
  7. Ecco. Sai di avere un set di risultati contenente le raccolte che volevi unire insieme. È quindi possibile aggiungere più fasi per filtrarlo ulteriormente, ordinarlo, applicare skip() e limit(). Praticamente tutto quello che vuoi.