sql >> Databasteknik >  >> NoSQL >> MongoDB

Hur man skriver fackliga frågor i mongoDB

Att göra fackföreningar i MongoDB på ett "SQL UNION"-sätt är möjligt med hjälp av aggregering tillsammans med uppslagningar, i en enda fråga.

Något så här:

    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.
    ]);

Här är förklaringen av hur det fungerar:

  1. Instantiera ett aggregate av alla samling av din databas som innehåller minst ett dokument. Om du inte kan garantera att någon samling av din databas inte kommer att vara tom, kan du lösa det här problemet genom att skapa någon sorts "dummy"-samling i din databas som innehåller ett enda tomt dokument som kommer att finnas där specifikt för att göra fackliga frågor.

  2. Gör det första steget i din pipeline att vara { $limit: 1 } . Detta tar bort alla dokument i samlingen utom det första.

  3. Ta bort alla fält i det återstående dokumentet med $project stadier:

    { $project: { _id: 1 } },
    { $project: { _id: 0 } }
    
  4. Ditt aggregat innehåller nu ett enda tomt dokument. Det är dags att lägga till uppslag för varje samling du vill förena. Du kan använda pipeline för att göra någon specifik filtrering, eller lämna localField och foreignField som null för att matcha hela samlingen.

    { $lookup: { from: 'collectionToUnion1', pipeline: [...], as: 'Collection1' } },
    { $lookup: { from: 'collectionToUnion2', pipeline: [...], as: 'Collection2' } },
    { $lookup: { from: 'collectionToUnion3', pipeline: [...], as: 'Collection3' } }
    
  5. Du har nu ett aggregat som innehåller ett enda dokument som innehåller 3 arrayer så här:

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

    Du kan sedan slå samman dem till en enda array med ett $project steg tillsammans med $concatArrays aggregeringsoperatör:

    {
      "$project" :
      {
        "Union" : { $concatArrays: ["$Collection1", "$Collection2", "$Collection3"] }
      }
    }
    
  6. Du har nu ett aggregat som innehåller ett enda dokument, i vilket det finns en array som innehåller din samling av samlingar. Det som återstår att göra är att lägga till en $unwind och en $replaceRoot steg för att dela upp din array i separata dokument:

    { $unwind: "$Union" },
    { $replaceRoot: { newRoot: "$Union" } }
    
  7. Voilà. Du vet att du har en resultatuppsättning som innehåller de samlingar du ville förena. Du kan sedan lägga till fler steg för att filtrera det ytterligare, sortera det, använda skip() och limit(). I stort sett vad du vill.



  1. Fel vid anslutning till MongoDb Atlas Server

  2. Redis flera prenumeranter

  3. WRONGTYPE Operation mot en tangent som har fel typ av värde php

  4. Finns det något sätt att atomiskt uppdatera två samlingar i MongoDB?