sql >> Databasteknik >  >> NoSQL >> MongoDB

Anpassade funktioner beräknade kolumner mongodb projektion

Du verkar tro att det är möjligt att anropa en JavaScript-funktion i aggregeringspipelinen, men du kan inte göra detta. Du misstar vad som faktiskt är "interpolation" av en variabel från ett funktionsresultat för exekvering inom pipelinen.

Till exempel Om jag gör detta:

var getNumbers = function() { return [ 1,2,3 ] };

Då kallar jag detta:

db.collection.aggregate([
    { "$project": {
        "mynums": getNumbers()
    }}  
])

Vad som faktiskt händer i JavaScript-skalet "interpoleras" värdena och "innan" instruktionen skickas till servern, så här:

db.collection.aggregate([
    { "$project": {
        "mynums": [1,2,3]
    }}  
])

För att ytterligare visa det, lagra en funktion "endast" på servern:

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

Försök sedan köra aggregeringssatsen:

db.collection.aggregate([
    { "$project": {
        "greeting": hello()
    }}  
])

Och det kommer att resultera i ett undantag:

E QUERY [main] ReferenceError:hej är inte definierad vid (skal):1:69

Vilket beror på att exekveringen sker på "klienten" och inte "servern" och funktionen finns inte på klienten.

Aggregeringsramverket kan inte kör JavaScript, eftersom det inte har någon bestämmelse för att göra det. Alla operationer utförs i inbyggd kod, utan att någon JavaScript-motor anropas. Därför använder du operatorerna där istället:

db.collection.aggregate([
    { "$project": {
        "total": { "$add": [ 1, 2 ] },
        "field_total": { "$subtract": [ "$gross", "$tax" ] }
    }}  
])   

Om du inte kan använda operatorerna för att uppnå resultaten så är det enda sättet du kan köra JavaScript-kod att köra mapReduce istället, som naturligtvis använder en JavaScript-motor för att gränssnitta med data från samlingen. Och därifrån kan du också hänvisa till en funktion på serversidan i din logik om du behöver:

{ "key": 1, "value": 1 },
{ "key": 1, "value": 2 },
{ "key": 1, "value": 3 }

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

db.collection.mapReduce(
    function() {
        emit(this.key,square(this.value))
    },
    function(key,values) {
        return Array.sum(values);
    },
    { "out": { "inline": 1 } }
)

Returnerar:

{
    "_id": 1,
    "value": 14
}

Så det här handlar inte om "hur man skickar in ett fältvärde" utan egentligen om det faktum att aggregeringsramverket inte stöder JavaScript på något sätt, och att det du trodde hände faktiskt inte är fallet.




  1. Installera och köra MongoDB på OSX

  2. golang + redis prestandaproblem med samtidighetsschemaläggaren

  3. Skäl för och emot att flytta från SQL-server till MongoDB

  4. Gruppera efter skick i MongoDB