sql >> Database >  >> NoSQL >> MongoDB

mongodb aggregatie framework match door geneste documenten

Het opvragen van deze structuur voor de gewenste resultaten is niet mogelijk zonder alle mogelijke forms te kennen namen vooraf en gebruik ze in de query. Het zou in ieder geval erg rommelig zijn. Dat gezegd hebbende, lees verder terwijl ik uitleg hoe het kan.

Er is een probleem met de structuur van deze documenten waardoor u geen redelijke query-analyse kunt uitvoeren. Zoals het er nu uitziet, zou je alle mogelijke formuliernaamvelden moeten kennen om iets uit te filteren.

Uw huidige structuur heeft formulieren die een subdocument bevatten, waarvan elke sleutel een ander subdocument bevat met een enkele eigenschap, status . Dit is moeilijk te doorkruisen aangezien uw forms element heeft een willekeurige structuur voor elk document dat u maakt. Dat betekent dat het patroon naar daalt naar de status informatie die u wijzigingen wilt vergelijken voor elk document in uw verzameling.

Dit is wat ik bedoel met pad. Om in elk element status te krijgen, moet je het volgende doen

Met het tweede element dat voortdurend verandert. Er is geen manier naar jokerteken zoiets als dit, aangezien de naamgeving als expliciet wordt beschouwd.

Dit kan worden beschouwd als een gemakkelijke manier om het serialiseren van de gegevens van uw formulieren te implementeren maar ik zie een flexibelere alternatief. Wat u nodig heeft, is een documentstructuur die u in een standaardpatroon kunt doorlopen. Dit is altijd iets dat het overwegen waard is in het ontwerp. Neem het volgende:

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

Dus de structuur van het document is gewijzigd om de forms . te maken element een Array, en in plaats van het statusveld onder een sleutel te plaatsen die het "formulierveld" noemt, hebben we elk lid van de Array als een subdocument dat het "formulierveld" bevat name en de status . Dus zowel de identifier als de status zijn nog steeds aan elkaar gekoppeld, maar worden nu gewoon weergegeven als een subdocument. Dit verandert vooral het toegangspad naar deze sleutels, zoals nu voor beide de veldnaam en zijn status kunnen we doen

Wat dit betekent dat u kunt zoeken naar de namen van alle velden in het form of alle status velden in het form , of zelfs alle documenten met een bepaalde name veld en bepaalde status . Dat is veel beter dan wat gedaan kon worden met de originele structuur.

Nu, in jouw specifieke geval, wil je alleen de documenten waar alle de velden zijn niet void . Nu is er geen enkele manier om dit in een enkele query te doen, omdat er geen operator is om alle elementen in een array op deze manier te vergelijken en te zien of ze hetzelfde zijn. Maar er zijn twee benaderingen die u kunt volgen:

De eerste en waarschijnlijk niet zo efficiënte manier is om alle op te vragen documenten die een element bevatten in forms die een status . heeft van "leegte". Met de resulterende document-ID's kunt u een andere query uitvoeren die de documenten retourneert die niet . doen hebben de id's die zijn opgegeven.

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

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

Gezien de resultaatgrootte is dit misschien niet mogelijk en is het over het algemeen geen goed idee als de uitsluitingsoperator $not forceert in feite een volledige scan van de collectie, dus je kon geen index gebruiken.

Een andere benadering is om de aggregatiepijplijn als volgt te gebruiken:

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

Natuurlijk zal dat alleen de _id retourneren voor de documenten die overeenkomen, maar je kunt een vraag stellen met $in en de hele overeenkomende documenten retourneren. Dit is beter dan de eerder gebruikte uitsluitingsoperator en nu kunnen we een index gebruiken om volledige collectiescans te vermijden.

Als laatste benadering en voor de beste prestatie-overweging, zou u het document opnieuw kunnen wijzigen zodat u op het hoogste niveau de "status" behoudt of een veld in de formulieren in "leeg" of "gesloten" is. Dus op het hoogste niveau zou de waarde alleen worden gesloten als alle items "gesloten" en "nietig" waren als iets nietig was, enzovoort.

Die laatste zou een verdere programmatische wijziging betekenen, en alle wijzigingen in de forms items zouden ook dit veld moeten bijwerken om de "status" te behouden. Het is echter de meest efficiënte manier om de documenten te vinden die u nodig hebt en kan het overwegen waard zijn.

BEWERKEN :

Afgezien van het wijzigen van het document om een ​​masterstatus te krijgen, is het snelste vraagformulier in de herziene structuur eigenlijk:

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



  1. Werken met geneste objecten in Redis?

  2. Node.js Kue hoe mislukte taken opnieuw te starten

  3. Kan geen bron uit de pool halen (SocketTimeoutException:)

  4. Ingegeven argument moet een enkele string van 12 bytes zijn