MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Utilizzo delle funzioni JavaScript archiviate nella pipeline di aggregazione, MapReduce o runCommand

Qualsiasi funzione salvata in system.js è disponibile per l'utilizzo da parte di istruzioni di elaborazione "JavaScript" come $where operatore e mapReduce e può essere referenziato da _id il valore è stato assegnato.

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

E alcuni dati inseriti per la raccolta "campione":

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

Quindi:

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

Dà:

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

O con $where :

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

Ma in "nessuno" caso puoi usare globali come il database db riferimento o altre funzioni. Entrambi $where e mapReduce la documentazione contiene informazioni sui limiti di ciò che puoi fare qui. Quindi, se pensavi di fare qualcosa come "cercare dati in un'altra raccolta", puoi dimenticarlo perché è "Non consentito".

Ogni L'azione del comando MongoDB è effettivamente comunque una chiamata a un'azione "runCommand" "sotto il cofano". Ma a meno che ciò che quel comando sta effettivamente facendo non sia "chiamare un motore di elaborazione JavaScript", l'utilizzo diventa irrilevante. Ci sono comunque solo pochi comandi che fanno questo, essendo mapReduce , group o eval e, naturalmente, le operazioni di ricerca con $where .

Il framework di aggregazione non utilizzare JavaScript in alcun modo. Potresti sbagliare proprio come altri hanno fatto un'affermazione come questa, che non fa quello che pensi che faccia:

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

Quindi è "non in esecuzione dentro " la pipeline di aggregazione, ma piuttosto il "risultato" di quel .distinct() la chiamata viene "valutata" prima che la pipeline venga inviata al server. Proprio come con una variabile esterna si fa comunque:

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

Entrambi essenzialmente inviano al server allo stesso modo:

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

Quindi "non è possibile" "chiamare" alcuna funzione JavaScript nella pipeline di aggregazione, né ha davvero senso "passare" i risultati in generale da qualcosa salvato in system.js . Il "codice" deve essere "caricato sul client" e solo un motore JavaScript può effettivamente fare qualsiasi cosa con esso.

Con il framework di aggregazione, tutti gli "operatori" disponibili sono in realtà funzioni codificate in modo nativo al contrario dell'interpretazione JavaScript "free form" fornita per mapReduce . Quindi, invece di scrivere "JavaScript", usi gli operatori stessi:

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

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

Quindi ci sono limitazioni su ciò che puoi fare con le funzioni salvate in system.js, ed è probabile che ciò che vuoi fare sia:

  • Non consentito, come l'accesso ai dati da un'altra raccolta
  • Non proprio richiesto in quanto la logica generalmente è comunque autonoma
  • O probabilmente implementato meglio nella logica del client o comunque in altra forma diversa

Quasi l'unico uso pratico a cui riesco davvero a pensare è che hai un numero di operazioni "mapReduce" che non possono essere eseguite in nessun altro modo e hai varie funzioni "condivise" che preferiresti semplicemente archiviare sul server piuttosto che mantenere all'interno di ogni chiamata alla funzione mapReduce.

Ma poi di nuovo, il motivo del 90% per mapReduce rispetto al framework di aggregazione è solitamente che la "struttura del documento" delle raccolte è stata scelta male e la funzionalità JavaScript è "necessaria" per attraversare il documento per la ricerca e l'analisi.

Quindi puoi usarlo con i vincoli consentiti, ma nella maggior parte dei casi probabilmente non dovresti usarlo affatto, ma risolvere gli altri problemi che ti hanno fatto credere di aver bisogno di questa funzione in primo luogo.