MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Mongodb mehrfach verschachtelte Array-Suche

Sie benötigen den .aggregate() -Methode, um Array-Inhalte nach mehr als einer einzelnen Übereinstimmung zu "filtern", und auch die grundlegende Übereinstimmung ist viel einfacher, da MongoDB sich nicht darum kümmert, dass sich die Daten innerhalb von Arrays befinden, solange der angegebene Pfad korrekt ist:

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

Bei PHP wird dies wie folgt notiert:

$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 ) ) )
))

Der $map Operator ermöglicht die Untersuchung jedes Elements des äußeren Arrays und übergibt jedes Element an $cond ternärer Betrieb. Dadurch wird ein $setIsSubset verarbeitet Operation auf dem "inneren" Array, um zu sehen, ob es tatsächlich einen der Werte in der alternativen Menge enthält (in diesem Fall [1] ) und wo ein true Auswertung erfolgt, dann wird das Element zurückgegeben oder andernfalls false .

Der Sinn von $setDifference ist, diese false zu entfernen Werte aus dem geänderten Array und geben nur übereinstimmende Elemente zurück. Und schließlich der $exists test prüft, ob das äußere Array tatsächlich mindestens ein Element enthält und als Ergebnis der Filterung nicht leer ist.

Die zurückgegebenen Dokumente sind diejenigen mit der übereinstimmenden Bedingung und nur die Array-Elemente, die auch der angegebenen Bedingung entsprechen.

Natürlich verlangen die Operatoren hier, dass Sie mindestens MongoDB 2.6 als Server haben (das ist jetzt eine ziemlich alte Version und zumindest ein empfohlenes Update), aber wenn Sie noch eine niedrigere Version haben, dann brauchen Sie einen traditionellen Ansatz mit $unwind und $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' )
        )
    )
))