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

MongoDB:contare quanti elementi con un determinato valore esistono in un array, che è in un documento?

Il quadro di aggregazione è l'ideale per questo. Prendi in considerazione l'esecuzione della seguente pipeline per ottenere il risultato desiderato.

pipeline = [
    {
        "$match": {
            "name": "james",
            "books.year": 1990
        }
    },
    {
        "$project": {
            "numberOfBooks": {
                "$size": {                  
                    "$filter": {
                        "input": "$books",
                        "as": "el",
                        "cond": { "$eq": [ "$$el.year", 1990 ] }
                    }                   
                }
            }
        }
    }
];
db.collection.pipeline(pipeline);

La pipeline di cui sopra utilizza il nuovo $filter operatore disponibile per MongoDB 3.2 per produrre un array che soddisfa la condizione specificata, ovvero filtra gli elementi esterni che non soddisfano i criteri. L'iniziale $match pipeline è necessario per filtrare i documenti che entrano nella pipeline di aggregazione all'inizio come strategia di ottimizzazione della pipeline.

Il $size operatore che accetta una singola espressione come argomento, quindi ti dà il numero di elementi nell'array risultante, quindi hai il conteggio del libro desiderato.

Per una soluzione alternativa che non utilizza il $filter operatore non trovato nelle versioni precedenti, considera la seguente operazione di pipeline:

pipeline = [
    {
        "$match": {
            "name": "james",
            "books.year": 1990
        }
    },
    {
        "$project": {
            "numberOfBooks": {
                "$size": {                  
                    "$setDifference": [
                        {
                            "$map": {
                                "input": "$books",
                                "as": "el",
                                "in": {
                                    "$cond": [
                                        { "$eq": [ "$$el.year", 1990 ] },
                                        "$$el",
                                        false
                                    ]
                                }
                            }
                        },
                        [false]
                    ]                   
                }
            }
        }
    }
];
db.collection.pipeline(pipeline);

Il $project la fase della pipeline prevede l'adattamento dell'array dei libri in modo da rimuovere i documenti che non hanno l'anno 1990. Ciò è possibile tramite il $setDifference e $map operatori.

Il $map in sostanza, l'operatore crea un nuovo campo di matrice che contiene i valori come risultato della logica valutata in una sottoespressione per ciascun elemento di una matrice. Il $setDifference l'operatore restituisce quindi un insieme con elementi che appaiono nel primo insieme ma non nel secondo insieme; cioè esegue un complemento relativo del secondo insieme rispetto al primo. In questo caso restituirà l'array di libri finale che ha elementi con l'anno 1990 e successivamente il $size calcola il numero di elementi nell'array risultante, dandoti così il conteggio del libro.

Per una soluzione che utilizza $unwind operatore, tenendo presente che (grazie a questa perspicace risposta di @BlakesSeven nei commenti):

e come ultima risorsa, esegui la seguente pipeline:

pipeline = [
    {
        "$match": {
            "name": "james",
            "books.year": 1990
        }
    },
    { "$unwind": "$books" },
    {
        "$match": { "books.year": 1990 }
    },
    {
        "$group": {
            "_id": null
            "count": { "$sum": 1 }
        }
    }
]
db.collection.pipeline(pipeline)