MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Verwenden gespeicherter JavaScript-Funktionen in der Aggregationspipeline, MapReduce oder runCommand

Jede Funktion, die Sie in system.js speichern steht zur Verwendung durch "JavaScript"-Verarbeitungsanweisungen wie $where zur Verfügung -Operator und mapReduce und kann über die _id referenziert werden Wert wurde zugewiesen.

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

Und einige Daten, die in die "Beispiel"-Sammlung eingefügt wurden:

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

Dann:

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

Gibt:

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

Oder mit $where :

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

Aber in "noch" keinem Fall können Sie Globals wie die Datenbank db verwenden Referenz oder andere Funktionen. Beide $where und mapReduce Dokumentation enthalten Informationen über die Grenzen dessen, was Sie hier tun können. Wenn Sie also dachten, Sie würden etwas tun wie „Daten in einer anderen Sammlung nachschlagen“, dann können Sie es vergessen, weil es „nicht erlaubt“ ist.

Alle MongoDB-Befehlsaktion ist tatsächlich sowieso ein Aufruf einer "runCommand"-Aktion "unter der Haube". Aber wenn dieser Befehl nicht tatsächlich "eine JavaScript-Verarbeitungs-Engine aufruft", wird die Verwendung irrelevant. Es gibt ohnehin nur wenige Befehle, die dies tun, nämlich mapReduce , group oder eval , und natürlich die Suchoperationen mit $where .

Das Aggregations-Framework tut dies nicht Verwenden Sie JavaScript in keiner Weise. Sie könnten sich irren, genauso wie andere eine Aussage wie diese gemacht haben, die nicht das tut, was Sie denken, dass sie es tut:

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

Das ist also „nicht innerhalb ausgeführt " die Aggregationspipeline, sondern das "Ergebnis" dieses .distinct() Der Aufruf wird "ausgewertet", bevor die Pipeline an den Server gesendet wird. Ähnlich wie bei einer externen Variable wird sowieso verfahren:

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

Beide senden im Wesentlichen auf die gleiche Weise an den Server:

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

Es ist also „nicht möglich“, irgendeine JavaScript-Funktion in der Aggregationspipeline „aufzurufen“, noch macht es wirklich Sinn, Ergebnisse im Allgemeinen von etwas zu „übergeben“, das in system.js gespeichert ist . Der "Code" muss "auf den Client geladen" werden und nur eine JavaScript-Engine kann tatsächlich etwas damit anfangen.

Mit dem Aggregationsframework sind alle verfügbaren „Operatoren“ tatsächlich nativ codierte Funktionen im Gegensatz zu der JavaScript-Interpretation in „freier Form“, die für mapReduce bereitgestellt wird . Anstatt "JavaScript" zu schreiben, verwenden Sie also die Operatoren selbst:

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

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

Es gibt also Einschränkungen, was Sie mit Funktionen tun können, die in system.js gespeichert sind, und die Chancen stehen gut, dass Sie Folgendes tun möchten:

  • Nicht zulässig, z. B. Zugriff auf Daten aus einer anderen Sammlung
  • Nicht wirklich erforderlich, da die Logik sowieso in sich abgeschlossen ist
  • Oder wahrscheinlich sowieso besser in Client-Logik oder einer anderen anderen Form implementiert

Die einzige praktische Verwendung, die mir wirklich einfällt, ist, dass Sie eine Reihe von "mapReduce" -Operationen haben, die auf keine andere Weise ausgeführt werden können, und Sie haben verschiedene "geteilte" Funktionen, die Sie lieber nur auf dem Server speichern als in jedem verwalten würden mapReduce-Funktionsaufruf.

Andererseits liegt der 90-prozentige Grund für mapReduce gegenüber dem Aggregationsframework normalerweise darin, dass die "Dokumentstruktur" der Sammlungen schlecht gewählt wurde und die JavaScript-Funktionalität "erforderlich" ist, um das Dokument für die Suche und Analyse zu durchlaufen.

Sie können es also unter den zulässigen Einschränkungen verwenden, aber in den meisten Fällen sollten Sie es wahrscheinlich überhaupt nicht verwenden, sondern die anderen Probleme beheben, die Sie glauben ließen, dass Sie diese Funktion überhaupt benötigen.