sql >> Databasteknik >  >> NoSQL >> MongoDB

Använda lagrade JavaScript-funktioner i Aggregation pipeline, MapReduce eller runCommand

Alla funktioner du sparar till system.js är tillgänglig för användning av "JavaScript"-bearbetningssatser som $where operator och mapReduce och kan refereras av _id värdet har tilldelats.

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

Och en del data infogade i "prov"-insamling:

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

Sedan:

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

Ger:

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

Eller med $where :

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

Men i "ingdera" fallet kan du använda globaler som databasen db referens eller andra funktioner. Båda $where och mapReduce dokumentationen innehåller information om gränserna för vad du kan göra här. Så om du trodde att du skulle göra något som "slå upp data i en annan samling", så kan du glömma det eftersom det är "Ej tillåtet".

Varje MongoDB kommandoåtgärd är faktiskt en uppmaning till en "runCommand"-åtgärd "under huven" i alla fall. Men om inte det kommandot faktiskt gör är att "anropa en JavaScript-bearbetningsmotor" så blir användningen irrelevant. Det finns ändå bara ett fåtal kommandon som gör detta, nämligen mapReduce , group eller eval , och naturligtvis sökoperationerna med $where .

Det gör aggregeringsramverket inte använda JavaScript på något sätt alls. Du kanske misstar dig precis som andra har gjort ett påstående som detta, som inte gör vad du tror att det gör:

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

Så det är "kör inte inuti " aggregeringspipelinen, utan snarare "resultatet" av den .distinct() anropet "utvärderas" innan pipelinen skickas till servern. Ungefär som med en extern variabel görs ändå:

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

Båda skickar i huvudsak till servern på samma sätt:

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

Så det är "inte möjligt" att "anropa" någon JavaScript-funktion i aggregeringspipelinen, och det finns inte heller någon mening med att "passera in" resultat i allmänhet från något sparat i system.js . "Koden" måste "laddas till klienten" och bara en JavaScript-motor kan faktiskt göra något med den.

Med aggregeringsramverket är alla tillgängliga "operatörer" faktiskt inbyggt kodade funktioner i motsats till JavaScript-tolkningen "fri form" som tillhandahålls för mapReduce . Så istället för att skriva "JavaScript" använder du själva operatorerna:

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

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

Så det finns begränsningar för vad du kan göra med funktioner sparade i system.js, och chansen är stor att det du vill göra är antingen:

  • Inte tillåtet, till exempel åtkomst till data från en annan samling
  • Inte nödvändigt eftersom logiken i allmänhet är fristående ändå
  • Eller förmodligen bättre implementerad i klientlogik eller annan annan form ändå

Nästan den enda praktiska användningen jag verkligen kan komma på är att du har ett antal "mapReduce"-operationer som inte kan göras på annat sätt och du har olika "delade" funktioner som du hellre bara lagrar på servern än att underhålla inom varje mapReduce funktionsanrop.

Men återigen, den 90 %-iga anledningen till mapReduce över aggregeringsramverket är vanligtvis att samlingarnas "dokumentstruktur" är dåligt vald och JavaScript-funktionaliteten "krävs" för att gå igenom dokumentet för sökning och analys.

Så du kan använda det under de tillåtna begränsningarna, men i de flesta fall borde du förmodligen inte använda det här alls, utan åtgärda de andra problemen som fick dig att tro att du behövde den här funktionen i första hand.




  1. Behåller Redis data?

  2. Få Spark, Python och MongoDB att fungera tillsammans

  3. Hur testar du dina MongoDB-applikationsuppgraderingar?

  4. Snabbaste sättet att lagra en numpy array i redis