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

mongodb aggregeringsrammematch af indlejrede dokumenter

Det er ikke muligt at forespørge på denne struktur for de ønskede resultater uden at kende alle de mulige forms navne på forhånd og bruge dem i forespørgslen. Det ville i hvert fald være meget rodet. Når det er sagt, så læs videre, mens jeg forklarer, hvordan det kan gøres.

Der er et problem med strukturen af ​​disse dokumenter, som vil forhindre dig i at udføre nogen rimelig forespørgselsanalyse. Som det står, skal du kende alle mulige formularnavnefelter for at filtrere noget fra.

Din nuværende struktur har formularer, der indeholder et underdokument, hvoraf hver nøgle indeholder et andet underdokument med en enkelt egenskab, status . Dette er svært at gennemgå som dine forms element har en vilkårlig struktur for hvert dokument, du opretter. Det betyder, at mønsteret skal falde ned til status oplysninger, du vil sammenligne ændringer for hvert dokument i din samling.

Her er hvad jeg mener med stien. For at få status i ethvert element skal du gøre følgende

Med det andet element, der ændrer sig hele tiden. Der er ingen måde til jokertegn noget i stil med dette, da navngivningen betragtes som eksplicit.

Dette kan have været betragtet som en nem måde at implementere serialisering af data fra dine formularer men jeg ser en mere fleksibel alternativ. Det, du har brug for, er en dokumentstruktur, du kan krydse i et standardmønster. Dette er altid noget, der er værd at overveje i design. Tag følgende:

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

Så strukturen af ​​dokumentet er ændret for at lave forms element en Array, og i stedet for at placere statusfeltet under en nøgle, der navngiver "formularfeltet", har vi hvert medlem af Arrayet som et underdokument, der indeholder "formfeltet" name og status . Så både identifikatoren og status er stadig parret sammen, men nu kun repræsenteret som et underdokument. Dette ændrer vigtigst af alt adgangsstien til disse nøgler, som nu for begge feltnavnet og dets status, vi kan gøre

Hvad dette betyder, at du kan forespørge for at finde navnene på alle felterne i form eller alle status felter i form , eller endda alle dokumenter med et bestemt name felt og visse status . Det er meget bedre end hvad der kunne gøres med den oprindelige struktur.

Nu i dit særlige tilfælde ønsker du at få kun dokumenterne hvor alle felterne er ikke void . Nu er der ingen måde i en enkelt forespørgsel at gøre dette, da der ikke er nogen operator til at sammenligne alle elementerne i et array på denne måde og se, om de er ens. Men der er to tilgange, du kan tage:

Den første og sandsynligvis ikke så effektive er at forespørge efter alle dokumenter, der indeholder et element i forms der har en status af "tomt". Med de resulterende dokument-id'er kan du udstede en anden forespørgsel, der returnerer de dokumenter, der ikke gør. har de id'er, der blev angivet.

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

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

I betragtning af resultatstørrelsen er dette muligvis ikke muligt og er generelt ikke en god idé, da ekskluderingsoperatoren $not tvinger dybest set en fuld scanning af samlingen, så du kunne ikke bruge et indeks.

En anden tilgang er at bruge aggregeringspipelinen som følger:

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" }}
])

Det vil selvfølgelig kun returnere _id for de dokumenter, der matcher, men du kan sende en forespørgsel med $in og returnere hele matchende dokumenter. Dette er bedre end den ekskluderingsoperator, der blev brugt før, og nu kan vi bruge et indeks for at undgå fulde samlingsscanninger.

Som en endelig tilgang og til det bedste præstationshensyn kunne du ændre dokumentet igen, så du på øverste niveau beholder "status" for, om ethvert felt i formularerne er "ugyldigt" eller "lukket". Så på det øverste niveau ville værdien kun blive lukket, hvis alle elementerne var "lukkede" og "ugyldige", hvis noget var ugyldigt, og så videre.

Den sidste ville betyde en yderligere programmatisk ændring og alle ændringer af forms elementer skal også opdatere dette felt for at bevare "status". Det er dog den mest effektive måde at finde de dokumenter, du har brug for, og det kan være værd at overveje.

REDIGER :

Bortset fra at ændre dokumentet til at have en masterstatus, er den hurtigste forespørgselsformular på den reviderede struktur faktisk:

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



  1. mongodb FindAndModify - opdater data

  2. Fremtrædende træk ved MapReduce – Vigtigheden af ​​MapReduce

  3. MongoDB diakritisk følsom søgning viser ikke alle accentuerede (ord med diakritisk tegn) rækker som forventet og omvendt

  4. Fejl under oprettelse af en samling i MongoDB