sql >> Databasteknik >  >> NoSQL >> MongoDB

Mongodb multi kapslade arraysökning

Du behöver .aggregate() metod för att "filtrera" något arrayinnehåll för mer än en singular matchning, och även den grundläggande matchningen är mycket enklare eftersom MongoDB inte bryr sig om att data finns inom arrayer, bara så länge den angivna sökvägen är korrekt:

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

Med PHP ser detta följande ut:

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

$map operatorn tillåter inspektion av varje element i den yttre arrayen och skickade varje element till strong>$cond ternär operation. Detta bearbetar en $setIsSubset operation på den "inre" arrayen för att se om den faktiskt innehåller ett av värdena i den alternativa uppsättningen (i detta fall [1] ) och där en true utvärdering görs sedan returneras elementet eller på annat sätt false .

Poängen med $setDifference är att ta bort dessa false värden från den modifierade matrisen och returnerar endast matchade element. Och slutligen $exists testet ser att den yttre arrayen faktiskt har minst ett element och inte är tom som ett resultat av filtreringen.

De dokument som returneras är de med det matchande villkoret och endast de arrayelement som också matchar det angivna villkoret.

Självklart kräver operatörerna här att du har minst MongoDB 2.6 som server (vilket är en ganska gammal version nu och en rekommenderad uppdatering åtminstone) men om du fortfarande har en mindre version behöver du ett traditionellt tillvägagångssätt med $unwind och $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' )
        )
    )
))



  1. MongoDB $replaceAll

  2. Jämför sträng-ID med BSON::ObjectId

  3. Hur undviker man Redis-samtal i Lua-skriptbegränsningar?

  4. Är det möjligt att byta namn på fält i utdata från en Mongo-fråga i PyMongo?