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

Rechercher un élément basé sur deux valeurs

Du dupe précédemment lié (possible) , une solution utilisant $where suivrait :

db.collection.find({
    "$where": function() {
        self = this;
        return this.actors.filter(function(actor) {
            return self.director._id === actor._id;
        }).length > 0
    }
})

Et l'autre approche suggérée qui utilise le cadre d'agrégation $redact pipeline :

db.collection.aggregate([
    { 
        "$redact": { 
            "$cond": [
                { 
                    "$setIsSubset": [ 
                        ["$director._id"], 
                        {
                            "$map": {
                                "input": "$actors",
                                "as": "el",
                                "in": "$$el._id"
                            }
                        }
                    ] 
                },
                "$$KEEP",
                "$$PRUNE"
            ]
        }
    }
])

Dans ce qui précède, la logique de condition pour $redact se fait grâce à l'utilisation d'opérateurs d'ensemble $setIsSubset et $map .

Le $map L'opérateur renverra un tableau contenant uniquement les identifiants d'acteur des actors tableau après avoir appliqué une expression à chaque élément du tableau. Ainsi, par exemple, l'expression

{
    "$map": {
        "input": "$actors",
        "as": "el",
        "in": "$$el._id"
    }
}

si appliqué sur le tableau des acteurs

[ 
    {
        "_id" : "artist:3",
        "first_name" : "James",
        "last_name" : "Stewart",
        "birth_date" : "1908",
        "role" : "John Ferguson"
    }, 
    {
        "_id" : "artist:16",
        "first_name" : "Kim",
        "last_name" : "Novak",
        "birth_date" : "1925",
        "role" : "Madeleine Elster"
    }, 
    {
        "_id" : "artist:282",
        "first_name" : "Arthur",
        "last_name" : "Pierre",
        "birth_date" : null,
        "role" : null
    }
]

reviendra

[ "artist:3", "artist:16", "artist:282" ]

Ce résultat est comparé à un tableau à un seul élément ["$directors._id"] en utilisant le $setIsSubset opérateur qui prend deux tableaux et renvoie true lorsque le premier tableau est un sous-ensemble du second, y compris lorsque le premier tableau est égal au second tableau, et false sinon.

Par exemple,

{ 
    "$setIsSubset": [ 
        [ "artist:12" ], 
        [ "artist:3", "artist:16", "artist:282" ] 
    ] 
}       // false

{ 
    $setIsSubset: [ 
        [ "artist:282" ], 
        [ "artist:3", "artist:16", "artist:282" ] 
    ] 
}       // true

Le résultat booléen de l'opérateur est ensuite utilisé comme base pour le $redact pipeline.

Les explications sur les performances sont toujours valables :$where est un bon hack si nécessaire, mais il doit être évité autant que possible.