2011-09-10 20 views
24

He estado buscando un ejemplo de cómo puedo transmitir el resultado de una consulta MongoDB a un cliente nodejs. Todas las soluciones que he encontrado hasta ahora parecen leer el resultado de la consulta de una vez y luego enviar el resultado de vuelta al servidor.Cómo transmitir los resultados de la consulta MongoDB con nodejs?

En lugar de eso, me gustaría (obviamente) proporcionar una devolución de llamada al método de consulta y hacer que MongoDB lo llame cuando esté disponible el siguiente fragmento del conjunto de resultados.

He estado buscando a la mangosta, ¿debería utilizar un controlador diferente?

Ene

Respuesta

25

Streaming en Mangosta llegó a estar disponible en la versión 2.4.0, que apareció three months después de haber publicado esta pregunta: ¿

Model.where('created').gte(twoWeeksAgo).stream().pipe(writeStream); 

más elaborada ejemplos se pueden encontrar en su documentation page.

+8

'Mongoose: Query.prototype.stream() está en desuso en mongoose> = 4.5.0, use Query.prototype.cursor() en su lugar ' –

9

mongoose no es realmente "conductor", en realidad es una envoltura alrededor del conductor ORM MongoDB (node-mongodb-native).

Para hacer lo que está haciendo, eche un vistazo al .find y .each método del controlador. Aquí hay algo de código a partir de los ejemplos:

// Find all records. find() returns a cursor 
collection.find(function(err, cursor) { 
    sys.puts("Printing docs from Cursor Each") 
    cursor.each(function(err, doc) { 
    if(doc != null) sys.puts("Doc from Each " + sys.inspect(doc)); 
    })      
}); 

para transmitir los resultados, que está básicamente la sustitución que sys.puts con su función de "corriente". No estoy seguro de cómo planea transmitir los resultados. Creo que puedes hacer response.write() + response.flush(), pero es posible que también quieras pagar socket.io.

+1

Gracias - el problema de controladores descubrí lo de ayer . La solución de búsqueda/cursor que esperaba, pero es sorprendentemente difícil encontrar ejemplos. La mayoría hace un descubrimiento y luego docs.foreach (...) –

+0

Actualización: En realidad, no conseguí que esto funcionara de la manera que usted describe. Lo que tuve que hacer es crear un EventEmitter para unir la secuencia de respuesta y la secuencia de datos desde el backend. –

+0

Tiene razón sobre los ejemplos, lo mejor que puede esperar es la carpeta "ejemplos" en el código fuente. 'EventEmitter' también suena correcto. Si tiene un buen ejemplo, definitivamente podemos actualizar esta respuesta con algo más detallado. –

2

Aquí está la solución que encontré (por favor, corríjanme nadie si thatis la manera equivocada de hacerlo): (También excusa la mala codificación - demasiado tarde para mí ahora embellecer este)

var sys = require('sys') 
var http = require("http"); 

var Db = require('/usr/local/src/npm/node_modules/mongodb/lib/mongodb').Db, 
    Connection = require('/usr/local/src/npm/node_modules/mongodb/lib/mongodb').Connection, 
    Collection = require('/usr/local/src/npm/node_modules/mongodb/lib/mongodb').Collection, 
    Server = require('/usr/local/src/npm/node_modules/mongodb/lib/mongodb').Server; 

var db = new Db('test', new Server('localhost',Connection.DEFAULT_PORT , {})); 

var products; 

db.open(function (error, client) { 
    if (error) throw error; 
    products = new Collection(client, 'products'); 
}); 

function ProductReader(collection) { 
     this.collection = collection; 
} 

ProductReader.prototype = new process.EventEmitter(); 

ProductReader.prototype.do = function() { 
     var self = this; 

     this.collection.find(function(err, cursor) { 
       if (err) { 
         self.emit('e1'); 
         return; 

       } 
       sys.puts("Printing docs from Cursor Each"); 

       self.emit('start'); 
       cursor.each(function(err, doc) { 
         if (!err) { 
           self.emit('e2'); 
           self.emit('end'); 
           return; 
         } 

         if(doc != null) { 
           sys.puts("doc:" + doc.name); 
           self.emit('doc',doc); 
         } else { 
           self.emit('end'); 
         } 
       }) 
     }); 
}; 
http.createServer(function(req,res){ 
     pr = new ProductReader(products); 
     pr.on('e1',function(){ 
       sys.puts("E1"); 
       res.writeHead(400,{"Content-Type": "text/plain"}); 
       res.write("e1 occurred\n"); 
       res.end(); 
     }); 
     pr.on('e2',function(){ 
       sys.puts("E2"); 
       res.write("ERROR\n"); 
     }); 

     pr.on('start',function(){ 
       sys.puts("START"); 
       res.writeHead(200,{"Content-Type": "text/plain"}); 
       res.write("<products>\n"); 
     }); 

     pr.on('doc',function(doc){ 
       sys.puts("A DOCUMENT" + doc.name); 
       res.write("<product><name>" + doc.name + "</name></product>\n"); 
     }); 

     pr.on('end',function(){ 
       sys.puts("END"); 
       res.write("</products>"); 
       res.end(); 
     }); 

     pr.do(); 

    }).listen(8000); 
22

node-mongodb-driver (la capa subyacente que usa cada cliente mongoDB en nodejs) excepto la API de cursor que otros mencionaron tiene una buena API de secuencia (#458). Lamentablemente no encontré documentado en otro lugar.

Actualización: there are docs también here.

Puede ser utilizado como esto:

var stream = collection.find().stream() 
stream.on('error', function (err) { 
    console.error(err) 
}) 
stream.on('data', function (doc) { 
    console.log(doc) 
}) 

En realidad implementa la interfaz ReadableStream, por lo que tiene todas las golosinas (pausa/reanudar etc)

+1

Encontré documentación sobre a qué se refiere @Dan Milon en http: // mongodb. github.com/ sitio web. aquí está [CusrsorStream] (http://mongodb.github.com/node-mongodb-native/api-generated/cursorstream.html) – ilikeopensource

+0

¡Ni siquiera sabía que esto existía! ¡Gracias! [mongodb.github.com/node-mongodb-native](http://mongodb.github.com/node-mongodb-native) eso es para el caso. –

+3

¡La mejor respuesta! ¡Y con un enlace de documentos! –

Cuestiones relacionadas