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

Mongodb ricerca di array multi nidificati

Hai bisogno di .aggregate() metodo per "filtrare" qualsiasi contenuto dell'array per più di una singola corrispondenza, e anche la corrispondenza di base è molto più semplice poiché a MongoDB non importa che i dati si trovino all'interno degli array, purché il percorso specificato sia corretto:

db.collection.aggregate([
    { "$match": { "data.userid": 1 } },
    { "$project": {
        "data": {
            "$setDifference": [
                { "$map": {
                    "input": "$data",
                    "as": "el",
                    "in": { 
                        "$cond": [
                            { "$setIsSubset": [ [1], "$$el.userid" ] },
                            "$$el",
                            false
                        ]
                    }
                }},
                [false]
            ]
        }
    }},
    { "$match": { "data.0": { "$exists": true } }}
])

Con PHP questo annota come segue:

$collection->aggregate(array(
    array( '$match' => array( "data.userid" => 1 )),
    array(
        '$project' => array(
            'data' => array(
                '$setDifference' => array(
                    array(
                        '$map' => array(
                            'input' => '$data',
                            'as' => 'el',
                            'in' => array(
                                '$cond' => array(
                                    array( '$setIsSubset' => array(array(1),'$$el.userid') ),
                                    '$$el',
                                    FALSE
                                )
                            )
                        )
                    ),
                    array(FALSE)
                )
            )
        )
    ),
    array( '$match' => array( 'data.0' => array( '$exists' => TRUE ) ) )
))

Il $map l'operatore consente l'ispezione di ogni elemento dell'array esterno e passa ogni elemento a $cond operazione ternaria. Questo elabora un $setIsSubset operazione sull'array "inner" per vedere se contiene effettivamente uno dei valori nell'insieme alternativo (in questo caso [1] ) e dove un true viene effettuata la valutazione, quindi l'elemento viene restituito o altrimenti false .

Il punto di $setDifference è rimuovere quei false valori dall'array modificato e restituiscono solo elementi corrispondenti. E infine il $exists test cerca di vedere che l'array esterno ha effettivamente almeno un elemento e non è vuoto come risultato del filtro.

I documenti restituiti sono quelli con la condizione di corrispondenza e solo gli elementi dell'array che soddisfano anche la condizione specificata.

Ovviamente gli operatori qui richiedono che tu abbia almeno MongoDB 2.6 come server (che ora è una versione piuttosto vecchia e almeno un aggiornamento consigliato) ma se hai ancora una versione inferiore, allora hai bisogno di un approccio tradizionale con $unwind e $group :

$collection->aggregate(array(
    array( '$match' => array( "data.userid" => 1 )),
    array( '$unwind' => '$data' ),
    array( '$match' => array( 'data.userid' => 1 )),
    array( 
        '$group' => array(
            '_id' => '$_id',
            'data' => array( '$push' => '$data' )
        )
    )
))