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

Utilisation de fonctions JavaScript stockées dans le pipeline d'agrégation, MapReduce ou runCommand

Toute fonction que vous enregistrez dans system.js est disponible pour une utilisation par les instructions de traitement "JavaScript" telles que $where opérateur et mapReduce et peut être référencé par le _id la valeur a été attribuée.

db.system.js.save({ 
   "_id": "squareThis", 
   "value": function(a) { return a*a } 
})

Et quelques données insérées dans la collection "échantillon":

{ "_id" : ObjectId("55aafd2bacbed38e06f9eccf"), "a" : 1 }
{ "_id" : ObjectId("55aafea6acbed38e06f9ecd0"), "a" : 2 }
{ "_id" : ObjectId("55aafeabacbed38e06f9ecd1"), "a" : 3 }

Ensuite :

db.sample.mapReduce(
    function() {
       emit(null, squareThis(this.a));
    },
    function(key,values) {
        return Array.sum(values);
    },
    { "out": { "inline": 1 } }
 );

Donne :

   "results" : [
            {
                    "_id" : null,
                    "value" : 14
            }
    ],

Ou avec $where :

db.sample.find(function() { return squareThis(this.a) == 9 })
{ "_id" : ObjectId("55aafeabacbed38e06f9ecd1"), "a" : 3 }

Mais dans "aucun" des cas, vous ne pouvez utiliser des variables globales telles que la base de données db référence ou d'autres fonctions. Les deux $where et mapReduce la documentation contient des informations sur les limites de ce que vous pouvez faire ici. Donc, si vous pensiez que vous alliez faire quelque chose comme "rechercher des données dans une autre collection", vous pouvez l'oublier car c'est "Non autorisé".

Tous L'action de la commande MongoDB est en fait un appel à une action "runCommand" "sous le capot" de toute façon. Mais à moins que cette commande ne fasse réellement "l'appel d'un moteur de traitement JavaScript", alors l'utilisation devient sans objet. De toute façon, il n'y a que quelques commandes qui font cela, à savoir mapReduce , group ou eval , et bien sûr les opérations de recherche avec $where .

Le cadre d'agrégation ne le fait pas utiliser JavaScript de quelque manière que ce soit. Vous vous trompez peut-être, tout comme d'autres ont fait une déclaration comme celle-ci, qui ne fait pas ce que vous pensez qu'elle fait :

db.sample.aggregate([
    { "$match": {
        "a": { "$in": db.sample.distinct("a") }
    }}
])

Donc, ce n'est "pas en cours d'exécution à l'intérieur " le pipeline d'agrégation, mais plutôt le "résultat" de ce .distinct() L'appel est "évalué" avant que le pipeline ne soit envoyé au serveur. Un peu comme avec une variable externe se fait de toute façon :

var items = [1,2,3];
db.sample.aggregate([
    { "$match": {
        "a": { "$in": items }
    }}
])

Les deux envoient essentiellement au serveur de la même manière :

db.sample.aggregate([
    { "$match": {
        "a": { "$in": [1,2,3] }
    }}
])

Il n'est donc "pas possible" d'"appeler" une fonction JavaScript dans le pipeline d'agrégation, et il n'y a pas vraiment d'intérêt à "transmettre" les résultats en général à partir de quelque chose enregistré dans system.js . Le "code" doit être "chargé sur le client" et seul un moteur JavaScript peut en faire quoi que ce soit.

Avec le framework d'agrégation, tous les "opérateurs" disponibles sont en fait des fonctions codées nativement par opposition à l'interprétation JavaScript "libre" fournie pour mapReduce . Ainsi, au lieu d'écrire "JavaScript", vous utilisez les opérateurs eux-mêmes :

db.sample.aggregate([
    { "$group": {
        "_id": null,
        "sqared": { "$sum": {
           "$multiply": [ "$a", "$a" ]
        }}
    }}
])

{ "_id" : null, "sqared" : 14 }

Il y a donc des limites à ce que vous pouvez faire avec les fonctions enregistrées dans system.js, et il y a de fortes chances que ce que vous vouliez faire soit :

  • Non autorisé, comme l'accès aux données d'une autre collection
  • Pas vraiment nécessaire car la logique est généralement autonome de toute façon
  • Ou probablement mieux implémenté dans la logique client ou une autre forme différente de toute façon

À peu près la seule utilisation pratique à laquelle je peux vraiment penser est que vous avez un certain nombre d'opérations "mapReduce" qui ne peuvent pas être effectuées autrement et que vous avez diverses fonctions "partagées" que vous préférez simplement stocker sur le serveur plutôt que de les maintenir dans chaque Appel de la fonction mapReduce.

Mais là encore, la raison à 90 % de mapReduce par rapport au cadre d'agrégation est généralement que la "structure de document" des collections a été mal choisie et que la fonctionnalité JavaScript est "nécessaire" pour parcourir le document à des fins de recherche et d'analyse.

Vous pouvez donc l'utiliser dans les limites autorisées, mais dans la plupart des cas, vous ne devriez probablement pas l'utiliser du tout, mais résoudre les autres problèmes qui vous ont fait croire que vous aviez besoin de cette fonctionnalité en premier lieu.