MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Recherche de tableaux multi-imbriqués Mongodb

Vous avez besoin du .aggregate() afin de "filtrer" tout contenu de tableau pour plus d'une correspondance singulière, et la correspondance de base est également beaucoup plus simple car MongoDB ne se soucie pas du fait que les données se trouvent dans des tableaux, tant que le chemin spécifié est correct :

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

Avec PHP, cela se traduit comme suit :

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

Le $map permet l'inspection de chaque élément du tableau externe et transmet chaque élément au $cond opération ternaire. Cela traite un $setIsSubset opération sur le tableau "interne" pour voir s'il contient en fait l'une des valeurs de l'ensemble alternatif (dans ce cas [1] ) et où un true l'évaluation est faite puis l'élément est retourné ou sinon false .

Le point de $setDifference est de supprimer ces false valeurs du tableau modifié et ne renvoient que les éléments correspondants. Et enfin le $exists test regarde pour voir que le tableau externe a en fait au moins un élément et n'est pas vide à la suite du filtrage.

Les documents renvoyés sont ceux avec la condition correspondante et uniquement les éléments du tableau qui correspondent également à la condition spécifiée.

Bien sûr, les opérateurs ici exigent que vous ayez au moins MongoDB 2.6 comme serveur (qui est une version assez ancienne maintenant et une mise à jour conseillée au moins) mais si vous avez toujours une version inférieure, vous avez besoin d'une approche traditionnelle avec $unwind et $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' )
        )
    )
))