sql >> Databáze >  >> NoSQL >> MongoDB

Použití uložených funkcí JavaScriptu v agregačním kanálu, MapReduce nebo runCommand

Jakákoli funkce, kterou uložíte do system.js je k dispozici pro použití pomocí příkazů zpracování "JavaScript", jako je $where operátor a mapReduce a lze na něj odkazovat pomocí _id hodnota je byla přiřazena.

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

A některá data vložená do "vzorkové" kolekce:

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

Potom:

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

Dává:

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

Nebo pomocí $where :

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

Ale v "žádném" případě můžete použít globální prvky, jako je databáze db referenční nebo jiné funkce. Oba $where a mapReduce dokumentace obsahuje informace o limitech toho, co zde můžete dělat. Takže pokud jste si mysleli, že uděláte něco jako „vyhledat data v jiné kolekci“, pak na to můžete zapomenout, protože je to „Není povoleno“.

Každý Akce příkazu MongoDB ve skutečnosti je každopádně volání akce "runCommand" "pod kapotou". Ale pokud to, co tento příkaz ve skutečnosti dělá, není „volání stroje pro zpracování JavaScriptu“, pak se použití stává irelevantním. Existuje jen několik příkazů, které to dělají, a to mapReduce , group nebo eval a samozřejmě operace hledání s $where .

Agregační rámec ne používat JavaScript jakýmkoliv způsobem. Možná se mýlíte, stejně jako ostatní udělali prohlášení jako toto, které nedělá to, co si myslíte, že dělá:

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

Takže to "neběží uvnitř " agregační kanál, ale spíše "výsledek" toho .distinct() volání je "vyhodnoceno" před odesláním kanálu na server. Stejně jako u externí proměnné se to stejně dělá:

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

Oba v podstatě odesílají na server stejným způsobem:

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

Takže „není možné“ „zavolat“ jakoukoli JavaScriptovou funkci v agregačním kanálu, ani ve skutečnosti neexistuje žádný smysl „předávání“ výsledků obecně z něčeho uloženého v system.js . „Kód“ musí být „nahrán do klienta“ a ve skutečnosti s ním může cokoli dělat pouze stroj JavaScript.

S agregačním rámcem jsou všechny dostupné „operátory“ ve skutečnosti nativně kódované funkce, na rozdíl od interpretace JavaScriptu „volné formy“ poskytované pro mapReduce . Takže místo psaní "JavaScript" použijete samotné operátory:

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

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

Existují tedy omezení toho, co můžete dělat s funkcemi uloženými v system.js, a je pravděpodobné, že to, co chcete udělat, je buď:

  • Není povoleno, například přístup k datům z jiné kolekce
  • Ve skutečnosti to není nutné, protože logika je obecně stejně uzavřená
  • Nebo je pravděpodobně lépe implementováno v klientské logice nebo v jiné jiné formě

Jediné praktické využití, které mě skutečně napadá, je, že máte řadu operací „mapReduce“, které nelze provést jiným způsobem, a máte různé „sdílené“ funkce, které byste raději pouze ukládali na server, než je udržovali v každém volání funkce mapReduce.

Ale znovu, 90% důvodem pro mapReduce oproti agregačnímu rámci je obvykle to, že „struktura dokumentu“ sbírek byla špatně zvolena a funkce JavaScriptu je „vyžadována“ k procházení dokumentu za účelem vyhledávání a analýzy.

Můžete ji tedy používat v rámci povolených omezení, ale ve většině případů byste ji pravděpodobně neměli používat vůbec, ale měli byste opravit další problémy, kvůli kterým jste se domnívali, že tuto funkci potřebujete.




  1. Správa AWS:Jak ušetřit 30 % na nákladech na hostování MongoDB

  2. Získání výjimky nulového ukazatele Mongo agregace pomocí jarních dat (dynamická pole)

  3. Úkol z celeru vždy ČEKÁ

  4. Nelze se připojit k Redis z Dockeru