sql >> Databasteknik >  >> NoSQL >> MongoDB

mongodb aggregeringsramverk matchar av kapslade dokument

Att fråga efter den här strukturen för de resultat du vill ha är inte möjligt utan att känna till alla möjliga forms namn i förväg och använda dem i frågan. Det skulle bli väldigt rörigt i alla fall. Som sagt, läs vidare när jag förklarar hur det kan göras.

Det finns ett problem med strukturen på dessa dokument som kommer att hindra dig från att göra någon rimlig frågeanalys. Som det ser ut måste du känna till alla möjliga formulärnamnsfält för att filtrera bort någonting.

Din nuvarande struktur har formulär som innehåller ett underdokument, av vilka varje nyckel innehåller ytterligare ett underdokument med en enda egenskap, status . Detta är svårt att ta sig igenom som dina forms elementet har en godtycklig struktur för varje dokument du skapar. Det betyder att mönstret ska sjunka till status information som du vill jämföra ändringar för varje dokument i din samling.

Här är vad jag menar med väg. För att få status i något element måste du göra följande

Med det andra elementet som ändras hela tiden. Det finns ingen möjlighet till jokertecken något liknande detta eftersom namngivningen anses vara explicit.

Detta kan ha ansetts vara ett enkelt sätt att implementera serialisering av data från dina formulär men jag ser en mer flexibel alternativ. Vad du behöver är en dokumentstruktur som du kan gå igenom i ett standardmönster. Detta är alltid något som är värt att tänka på i design. Ta följande:

{
    "_id" : "Tvq444454j",
    "name": "Jim",
    "forms": [
        {
             "name": "Jorney",
             "status":"closed"          
        },
        {
            "name": "Women",
            "status":"void"            
        },
        {
            "name": "Child",
            "status":"closed"           
        },
        {
            "name": "Farm",
            "status":"closed"            
        }  
    ]
}

Så strukturen på dokumentet ändras för att göra forms element en Array, och istället för att placera statusfältet under en nyckel som namnger "formulärfältet" har vi varje medlem av Arrayen som ett underdokument som innehåller "formulärfältet" name och status . Så både identifieraren och statusen är fortfarande ihopparade men bara representerade som ett underdokument nu. Detta ändrar framför allt åtkomstvägen till dessa nycklar, som nu för båda fältnamnet och dess status kan vi göra

Vad det här betyder att du kan fråga för att hitta namnen på alla fält i form eller all status fält i form , eller till och med alla dokument med ett visst name fält och viss status . Det är mycket bättre än vad som kunde göras med den ursprungliga strukturen.

Nu i just ditt fall vill du få endast dokumenten där alla fälten är inte void . Nu finns det inget sätt i en enda fråga att göra detta eftersom det inte finns någon operatör för att jämföra alla element i en array på detta sätt och se om de är samma. Men det finns två tillvägagångssätt du kan ta:

Den första och förmodligen inte lika effektiva är att fråga efter alla dokument som innehåller ett element i forms som har en status av "tomt". Med de resulterande dokument-ID:na kan du skicka en annan fråga som returnerar de dokument som inte gör det har de id som angavs.

db.forms.find({ "forms.status": "void" },{ _id: 1})

db.forms.find({ _id: $not: { $in: [<Object1>,<Object2>,<Object3>,... ] } })

Med tanke på resultatstorleken kanske detta inte är möjligt och är i allmänhet inte en bra idé eftersom uteslutningsoperatorn $not tvingar i princip en fullständig genomsökning av samlingen, så du kunde inte använda ett index.

Ett annat tillvägagångssätt är att använda aggregeringspipelinen enligt följande:

db.forms.aggregate([
    { "$unwind": "$forms" },
    { "$group": { "_id": "$_id", "status": { "$addToSet": "$forms.status" }}},
    { "$unwind": "$status" },
    { "$sort": { "_id": 1, "status": -1 }},
    { "$group": { "_id": "$_id", "status": { "$first": "$status"}}},
    { "$match":{ "status": "closed" }}
])

Naturligtvis kommer det bara att returnera _id för de dokument som matchar, men du kan skicka en fråga med $in och returnera hela matchande dokument. Detta är bättre än uteslutningsoperatorn som användes tidigare, och nu kan vi använda ett index för att undvika fullständiga samlingsskanningar.

Som ett sista tillvägagångssätt och för det bästa prestationsövervägande, kan du ändra dokumentet igen så att du på översta nivån behåller "status" på om något fält i formulären är "void" eller "closed". Så på den översta nivån skulle värdet endast stängas om alla objekt var "stängda" och "ogiltiga" om något var ogiltigt, och så vidare.

Den sista skulle innebära ytterligare en programmatisk förändring och alla ändringar av forms objekt skulle behöva uppdatera detta fält också för att behålla "statusen". Det är dock det mest effektiva sättet att hitta de dokument du behöver och kan vara värt att överväga.

REDIGERA :

Bortsett från att ändra dokumentet för att ha en huvudstatus, är det snabbaste frågeformuläret i den reviderade strukturen faktiskt:

db.forms.find({ "forms": { "$not": { "$elemMatch": { "status": "void" } } } })



  1. ElasticSearch och sökning på flera fält i PHP

  2. Ember-data och MongoDB, hur man hanterar _id

  3. MongoDB Valfritt Unikt Index

  4. Sortera arrayen i dokumentet med MongoDB