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

Brugerdefinerede funktioner beregnede kolonner mongodb projektion

Du synes at tro, at det er muligt at kalde en JavaScript-funktion i aggregeringspipelinen, men du kan ikke gøre dette. Du tager fejl af, hvad der faktisk er "interpolation" af en variabel fra et funktionsresultat til udførelse inden for pipelinen.

For eksempel hvis jeg gør dette:

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

Så kalder jeg dette:

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

Så hvad der faktisk sker i JavaScript-skallen, bliver værdierne "interpoleret" og "før" instruktionen sendes til serveren, sådan her:

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

For yderligere at demonstrere det, gem en funktion "kun" på serveren:

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

Prøv derefter at køre aggregeringssætningen:

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

Og det vil resultere i en undtagelse:

E QUERY [main] ReferenceError:hej er ikke defineret på (shell):1:69

Hvilket skyldes, at eksekveringen sker på "klienten" og ikke "serveren", og funktionen eksisterer ikke på klienten.

Aggregeringsrammen kan ikke køre JavaScript, da det ikke har nogen bestemmelse til at gøre det. Alle handlinger udføres i indbygget kode, uden at der aktiveres nogen JavaScript-motor. Derfor bruger du i stedet operatorerne der:

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

Hvis du ikke kan bruge operatorerne til at opnå resultaterne, så er den eneste måde, du kan køre JavaScript-kode på, at køre mapReduce i stedet, som selvfølgelig bruger en JavaScript-motor til at interface med data fra samlingen. Og derfra kan du også henvise til en serversidefunktion i din logik, hvis du har brug for at:

{ "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 } }
)

Returnerer:

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

Så det her handler ikke om "hvordan man sender en feltværdi", men i virkeligheden om det faktum, at aggregeringsrammen ikke understøtter JavaScript på nogen måde, og at det, du troede skete, faktisk ikke er tilfældet.




  1. Slet alt i en MongoDB-database

  2. Tilføj felt, der ikke er i skemaet med mongoose

  3. Problem med at deserialisere redis-cache til objekter i Spring-boot

  4. Redis cluster failover:slave bliver ikke master