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

MongoDB :Agrégation utilisant $cond avec $regex

MISE À JOUR : À partir de MongoDB v4.1.11, il semble enfin y avoir une bonne solution à votre problème qui est documentée ici .

Réponse originale :

Comme je l'ai écrit dans les commentaires ci-dessus, $regex ne fonctionne pas dans $cond à partir de maintenant. Il y a un ticket JIRA ouvert pour ça mais c'est, euh, eh bien, ouvert...

Dans votre cas spécifique, j'aurais tendance à vous suggérer de résoudre ce sujet côté client, à moins que vous n'ayez affaire à des quantités folles de données d'entrée dont vous ne renverrez toujours que de petits sous-ensembles. À en juger par votre requête, il semblerait que vous allez toujours récupérer tous les documents regroupés en deux groupes de résultats ("Oui" et "Non").

Si vous ne voulez pas ou ne pouvez pas résoudre ce sujet côté client, alors voici quelque chose qui utilise $facette (MongoDB>=v3.4 requis) - ce n'est ni particulièrement rapide ni trop joli mais cela pourrait vous aider à démarrer.

db.captions.aggregate([{
    $facet: { // create two stages that will be processed using the full input data set from the "captions" collection
        "CallToActionYes": [{ // the first stage will...
            $match: { // only contain documents...
                "plainText": /leave\sa\scomment/i // that are allowed by the $regex filter (which could be extended with multiple $or expressions or changed to $in/$nin which accept regular expressions, too)
            }
        }, {
            $addFields: { // for all matching documents...
                "CallToAction": "Yes" // we create a new field called "CallsToAction" which will be set to "Yes"
            }
        }],
        "CallToActionNo": [{ // similar as above except we're doing the inverse filter using $not
            $match: {
                "plainText": { $not: /leave\sa\scomment/i }
            }
        }, {
            $addFields: {
                "CallToAction": "No" // and, of course, we set the field to "No"
            }
        }]
    }
}, {
    $project: { // we got two arrays of result documents out of the previous stage
        "allDocuments" : { $setUnion: [ "$CallToActionYes", "$CallToActionNo" ] } // so let's merge them into a single one called "allDocuments"
    }
}, {
    $unwind: "$allDocuments" // flatten the "allDocuments" result array
}, {
    $replaceRoot: { // restore the original document structure by moving everything inside "allDocuments" up to the top
        newRoot: "$allDocuments"
    }
}, {
    $project: { // include only the two relevant fields in the output (and the _id)
        "videoId": 1,
        "CallToAction": 1
    }
}])

Comme toujours avec le cadre d'agrégation, il peut être utile de supprimer des étapes individuelles à la fin du pipeline et d'exécuter la requête partielle afin de comprendre ce que fait chaque étape individuelle.