sql >> Database >  >> NoSQL >> MongoDB

Aangepaste functies berekende kolommen mongodb-projectie

U lijkt te denken dat het mogelijk is om een ​​JavaScript-functie in de aggregatiepijplijn aan te roepen, maar u kunt dit niet doen. Je verwart wat eigenlijk "interpolatie" is van een variabele van een functieresultaat voor uitvoering binnen de pijplijn.

Als ik dit bijvoorbeeld doe:

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

Dan noem ik dit:

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

Wat er dan feitelijk gebeurt in de JavaScript-shell, de waarden worden "geïnterpoleerd" en "voordat" de instructie naar de server wordt verzonden, als volgt:

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

Om dat verder aan te tonen, slaat u een functie "alleen" op de server op:

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

Probeer vervolgens de aggregatieverklaring uit te voeren:

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

En dat resulteert in een uitzondering:

E QUERY [main] ReferenceError:hallo is niet gedefinieerd op (shell)::1:69

Dat komt omdat de uitvoering plaatsvindt op de "client" en niet op de "server" en de functie niet op de client bestaat.

Het aggregatieraamwerk kan niet voer JavaScript uit, omdat het geen voorziening heeft om dit te doen. Alle bewerkingen worden uitgevoerd in native code, zonder dat er een JavaScript-engine wordt aangeroepen. Daarom gebruik je in plaats daarvan de operators:

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

Als u de operators niet kunt gebruiken om de resultaten te krijgen, kunt u alleen JavaScript-code uitvoeren door in plaats daarvan mapReduce uit te voeren, die natuurlijk een JavaScript-engine gebruikt om te communiceren met de gegevens uit de verzameling. En van daaruit kunt u ook verwijzen naar een server-side-functie binnen uw logica als dat nodig is:

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

Retourneren:

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

Dit gaat dus niet over "hoe een veldwaarde door te geven" maar echt over het feit dat het aggregatieraamwerk JavaScript op geen enkele manier ondersteunt, en dat wat u dacht dat er gebeurde, niet echt het geval is.




  1. Stuur:de toegang is geweigerd om het eigendom op te lossen omdat het geen eigen eigendom is van de ouder

  2. Mongoose Unieke index werkt niet!

  3. Voorwaarden voor meerdere deelname met behulp van de $lookup-operator

  4. Hoe documenten te verwijderen door efficiënt te zoeken in Mongo?