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

Brug af lagrede JavaScript-funktioner i Aggregation-pipelinen, MapReduce eller runCommand

Enhver funktion, du gemmer i system.js er tilgængelig til brug af "JavaScript"-behandlingsudsagn såsom $where operator og mapReduce og kan henvises til med _id værdi er blev tildelt.

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

Og nogle data indsat til "sample"-indsamling:

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

Så:

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

Giver:

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

Eller med $where :

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

Men i "ingen af" tilfælde kan du bruge globaler såsom databasen db reference eller andre funktioner. Begge $where og mapReduce dokumentationen indeholder oplysninger om grænserne for, hvad du kan gøre her. Så hvis du troede, du ville gøre noget som "slå data op i en anden samling", så kan du glemme det, fordi det er "Ikke tilladt".

Hver MongoDB kommandohandling er faktisk et opkald til en "runCommand"-handling "under motorhjelmen" alligevel. Men medmindre det, den kommando faktisk gør, er at "kalde en JavaScript-behandlingsmotor", så bliver brugen irrelevant. Der er alligevel kun nogle få kommandoer, der gør dette, nemlig mapReduce , group eller eval , og selvfølgelig find-operationerne med $where .

Det gør aggregeringsrammen ikke bruge JavaScript på nogen måde overhovedet. Du tager måske fejl, ligesom andre har lavet en udtalelse som denne, som ikke gør, hvad du tror, ​​den gør:

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

Så det er "ikke kører inde " aggregeringspipelinen, men snarere "resultatet" af den .distinct() opkaldet "evalueres", før pipelinen sendes til serveren. Meget som med en ekstern variabel gøres alligevel:

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

Begge sender i det væsentlige til serveren på samme måde:

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

Så det er "ikke muligt" at "kalde" en hvilken som helst JavaScript-funktion i aggregeringspipelinen, og der er heller ikke rigtig nogen mening med at "passere ind" resultater generelt fra noget gemt i system.js . "Koden" skal "indlæses til klienten", og kun en JavaScript-motor kan faktisk gøre noget med den.

Med aggregeringsrammen er alle tilgængelige "operatører" faktisk indbygget kodede funktioner i modsætning til JavaScript-fortolkningen af ​​"fri form" til rådighed for mapReduce . Så i stedet for at skrive "JavaScript", bruger du selve operatorerne:

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

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

Så der er begrænsninger for, hvad du kan gøre med funktioner gemt i system.js, og chancerne er, at det, du vil gøre, er enten:

  • Ikke tilladt, f.eks. adgang til data fra en anden samling
  • Ikke rigtig påkrævet, da logikken generelt er selvstændig alligevel
  • Eller sandsynligvis bedre implementeret i klientlogik eller anden anden form alligevel

Næsten den eneste praktiske brug, jeg virkelig kan komme i tanke om, er, at du har en række "mapReduce"-operationer, som ikke kan gøres på anden måde, og du har forskellige "delte" funktioner, som du hellere vil gemme på serveren end vedligeholde inden for hver mapReduce funktionskald.

Men igen, 90 % årsagen til mapReduce i forhold til aggregeringsrammen er normalt, at samlingernes "dokumentstruktur" er blevet dårligt valgt, og JavaScript-funktionaliteten er "påkrævet" for at gennemse dokumentet til søgning og analyse.

Så du kan bruge det under de tilladte begrænsninger, men i de fleste tilfælde burde du nok slet ikke bruge dette, men løse de andre problemer, der fik dig til at tro, at du havde brug for denne funktion i første omgang.




  1. Tips til lagring af MongoDB-sikkerhedskopier i skyen

  2. Brug redis til at bygge en realtidschat med socket.io og NodeJs

  3. Forespørgsel med strengdatoformat i mongodb

  4. Er ikke-blokerende Redis pubsub muligt?