sql >> Database >  >> NoSQL >> MongoDB

Opgeslagen JavaScript-functies gebruiken in de aggregatiepijplijn, MapReduce of runCommand

Elke functie die u opslaat in system.js is beschikbaar voor gebruik door "JavaScript"-verwerkingsinstructies zoals de $where operator en mapReduce en waarnaar kan worden verwezen door de _id waarde is toegewezen.

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

En enkele gegevens ingevoegd in de "sample"-verzameling:

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

Dan:

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

Geeft:

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

Of met $where :

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

Maar in "geen van beide" gevallen kun je globals gebruiken zoals de database db referentie of andere functies. Beide $where en mapReduce documentatie bevat informatie over de limieten van wat u hier kunt doen. Dus als je dacht dat je zoiets zou gaan doen als "gegevens opzoeken in een andere verzameling", dan kun je het vergeten omdat het "Niet toegestaan" is.

Elke MongoDB-opdrachtactie is eigenlijk een oproep tot een "runCommand" -actie "onder de motorkap" hoe dan ook. Maar tenzij wat die opdracht feitelijk doet "een JavaScript-verwerkingsengine aanroept", wordt het gebruik irrelevant. Er zijn sowieso maar een paar commando's die dit doen, namelijk mapReduce , group of eval , en natuurlijk de zoekbewerkingen met $where .

Het aggregatieraamwerk doet niet JavaScript op welke manier dan ook gebruiken. U kunt zich vergissen, net zoals anderen een verklaring als deze hebben gedaan, die niet doet wat u denkt dat het doet:

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

Dus dat is "niet binnen uitgevoerd" " de aggregatiepijplijn, maar eerder het "resultaat" van die .distinct() aanroep wordt "geëvalueerd" voordat de pijplijn naar de server wordt verzonden. Veel zoals met een externe variabele gebeurt sowieso:

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

Beide zenden in wezen op dezelfde manier naar de server:

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

Het is dus "niet mogelijk" om een ​​JavaScript-functie in de aggregatiepijplijn te "aanroepen", en het heeft ook geen zin om resultaten in het algemeen "door te geven" van iets dat is opgeslagen in system.js . De "code" moet "naar de client worden geladen" en alleen een JavaScript-engine kan er daadwerkelijk iets mee doen.

Met het aggregatieraamwerk zijn alle beschikbare "operators" eigenlijk native gecodeerde functies, in tegenstelling tot de "vrije vorm" JavaScript-interpretatie die wordt geboden voor mapReduce . Dus in plaats van "JavaScript" te schrijven, gebruik je de operators zelf:

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

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

Er zijn dus beperkingen aan wat u kunt doen met functies die zijn opgeslagen in system.js, en de kans is groot dat u ofwel:

  • Niet toegestaan, zoals toegang tot gegevens uit een andere verzameling
  • Niet echt vereist omdat de logica over het algemeen toch op zichzelf staat
  • Of toch waarschijnlijk beter geïmplementeerd in clientlogica of een andere andere vorm

Zowat het enige praktische nut dat ik kan bedenken, is dat je een aantal "mapReduce"-bewerkingen hebt die niet op een andere manier kunnen worden gedaan en dat je verschillende "gedeelde" functies hebt die je liever gewoon op de server opslaat dan onderhoudt binnen elke mapReduce functie-aanroep.

Maar nogmaals, de 90% reden voor mapReduce boven het aggregatieraamwerk is meestal dat de "documentstructuur" van de collecties slecht is gekozen en dat de JavaScript-functionaliteit "vereist" is om het document te doorzoeken voor zoeken en analyseren.

U kunt het dus gebruiken onder de toegestane beperkingen, maar in de meeste gevallen zou u dit waarschijnlijk helemaal niet moeten gebruiken, maar de andere problemen moeten oplossen waardoor u dacht dat u deze functie überhaupt nodig had.




  1. MongoDB Query Help - query op waarden van een sleutel in een subobject

  2. MongoDB $toDouble

  3. nginx lua redis cookie niet ingesteld

  4. MongoDB $replaceAll