我一直在寻找一个如何将MongoDB查询的结果流式传输到nodejs客户端的示例。到目前为止,我找到的所有解决方案似乎都会立即读取查询结果,然后将结果发送回服务器。
相反,我(显然)希望提供一个回调查询方法,并让MongoDB在结果集的下一个块可用时调用它。
我一直在看猫鼬 - 我应该使用不同的驱动程序吗?
扬
答案 0 :(得分:27)
在发布此问题之后,版本2.4.0中出现了Mongoose中的流式传输three months:
Model.where('created').gte(twoWeeksAgo).stream().pipe(writeStream);
可以在documentation page上找到更详细的例子。
答案 1 :(得分:26)
node-mongodb-driver
(每个mongoDB客户端在nodejs中使用的底层)除了其他人提到的游标API有一个很好的流API(#458)。不幸的是,我没有在其他地方找到它。
更新:there are docs也here。
可以像这样使用:
var stream = collection.find().stream()
stream.on('error', function (err) {
console.error(err)
})
stream.on('data', function (doc) {
console.log(doc)
})
它实际上实现了ReadableStream接口,因此它具有所有好处(暂停/恢复等)
答案 2 :(得分:10)
mongoose
实际上不是“驱动程序”,它实际上是MongoDB驱动程序(node-mongodb-native
)的ORM包装器。
要执行您正在执行的操作,请查看驱动程序的.find
和.each
方法。以下是示例中的一些代码:
// 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));
})
});
要对结果进行流式传输,您基本上用“流”功能替换sys.puts
。不确定您打算如何流式传输结果。我认为您可以response.write() + response.flush()
,但您可能还想结帐socket.io
。
答案 3 :(得分:2)
这是我找到的解决方案(如果这是错误的方法,请纠正我的任何人): (也可以原谅糟糕的编码 - 现在为时尚晚,以此来美化)
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);
答案 4 :(得分:0)
我自己一直在研究mongodb流,虽然我没有您想要的全部答案,但我确实有一部分。 您可以设置一个socket.io流
这是使用NPM上的javascript socket.io和socket.io-streaming 也为数据库使用mongodb,因为 使用有问题的40年历史数据库不正确,该进行现代化了 还有40岁的数据库是SQL,而据我所知SQL不会做流
因此,尽管您只询问了从服务器到客户端的数据,但我也想在客户端中获取从客户端到服务器的数据,因为在搜索时我永远找不到任何地方,并且我想在发送和接收位置设置一个位置流中的元素,这样每个人都可以很快掌握它。
客户端通过流发送数据到服务器
stream = ss.createStream();
blobstream=ss.createBlobReadStream(data);
blobstream.pipe(stream);
ss(socket).emit('data.stream',stream,{},function(err,successful_db_insert_id){
//if you get back the id it went into the db and everything worked
});
服务器从客户端接收流,然后在完成后进行回复
ss(socket).on('data.stream.out',function(stream,o,c){
buffer=[];
stream.on('data',function(chunk){buffer.push(chunk);});
stream.on('end',function(){
buffer=Buffer.concat(buffer);
db.insert(buffer,function(err,res){
res=insertedId[0];
c(null,res);
});
});
});
//这是获取数据并将其流式传输到客户端的另一半
客户端从服务器请求和接收流数据
stream=ss.createStream();
binarystring='';
stream.on('data',function(chunk){
for(var I=0;i<chunk.length;i++){
binarystring+=String.fromCharCode(chunk[i]);
}
});
stream.on('end',function(){ data=window.btoa(binarystring); c(null,data); });
ss(socket).emit('data.stream.get,stream,o,c);
服务器端回复流数据请求
ss(socket).on('data.stream.get',function(stream,o,c){
stream.on('end',function(){
c(null,true);
});
db.find().stream().pipe(stream);
});
最后一个是我仅有的一种,因为我还没有尝试过,所以我只是将它从屁股上拉出来了,但是应该可以。我实际上做了类似的事情,但是我将文件写入硬盘,然后使用fs.createReadStream将其流式传输到客户端。因此,不确定100%是否正确,但根据我的阅读结果,我会在测试后立即与您联系。
P.s。任何人都想问我关于我口语交流的方式,我是加拿大人,我喜欢说“ eh”带着你的拥抱冲我,击中兄弟/ sis':D