sql >> Base de Datos >  >> NoSQL >> MongoDB

Uso de funciones de JavaScript almacenadas en la canalización de agregación, MapReduce o runCommand

Cualquier función que guarde en system.js está disponible para su uso por sentencias de procesamiento de "JavaScript" como $where operador y mapReduce y puede ser referenciado por el _id se asignó el valor.

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

Y algunos datos insertados en la colección "muestra":

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

Entonces:

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

Da:

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

O con $where :

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

Pero en "ninguno de los casos" puede usar globales como la base de datos db referencia u otras funciones. Ambos $where y mapReduce La documentación contiene información sobre los límites de lo que puede hacer aquí. Entonces, si pensó que iba a hacer algo como "buscar datos en otra colección", puede olvidarlo porque está "No permitido".

Cada La acción del comando MongoDB es en realidad una llamada a una acción "runCommand" "debajo del capó" de todos modos. Pero a menos que lo que ese comando realmente esté haciendo sea "llamar a un motor de procesamiento de JavaScript", entonces el uso se vuelve irrelevante. De todos modos, solo hay unos pocos comandos que hacen esto, siendo mapReduce , group o eval , y por supuesto las operaciones de búsqueda con $where .

El marco de agregación no usar JavaScript de ninguna manera. Es posible que se esté confundiendo al igual que otros han hecho una declaración como esta, que no hace lo que cree que hace:

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

Así que "no se ejecuta dentro " la canalización de agregación, sino el "resultado" de ese .distinct() la llamada se "evalúa" antes de que la canalización se envíe al servidor. Tanto como con una variable externa se hace de todos modos:

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

Ambos esencialmente envían al servidor de la misma manera:

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

Por lo tanto, "no es posible" "llamar" a ninguna función de JavaScript en la canalización de agregación, ni tampoco tiene sentido "pasar" los resultados en general de algo guardado en system.js . El "código" debe "cargarse en el cliente" y solo un motor de JavaScript puede hacer algo con él.

Con el marco de agregación, todos los "operadores" disponibles son en realidad funciones codificadas de forma nativa a diferencia de la interpretación de JavaScript de "forma libre" proporcionada para mapReduce . Entonces, en lugar de escribir "JavaScript", usa los operadores mismos:

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

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

Por lo tanto, existen limitaciones sobre lo que puede hacer con las funciones guardadas en system.js, y lo más probable es que lo que quiera hacer sea:

  • No permitido, como acceder a datos de otra colección
  • Realmente no es necesario ya que la lógica generalmente es independiente de todos modos
  • O probablemente mejor implementado en la lógica del cliente u otra forma diferente de todos modos

Casi el único uso práctico que realmente se me ocurre es que tiene una serie de operaciones "mapReduce" que no se pueden hacer de otra manera y tiene varias funciones "compartidas" que preferiría simplemente almacenar en el servidor que mantener dentro de cada llamada a la función mapReduce.

Pero, de nuevo, la razón del 90% para mapReduce sobre el marco de agregación es que la "estructura del documento" de las colecciones se ha elegido mal y la funcionalidad de JavaScript es "requerida" para recorrer el documento para la búsqueda y el análisis.

Por lo tanto, puede usarlo bajo las restricciones permitidas, pero en la mayoría de los casos probablemente no debería usar esto en absoluto, sino solucionar los otros problemas que le hicieron creer que necesitaba esta función en primer lugar.