NodeJS/Mongo:通过各种集合循环查询
Posted
技术标签:
【中文标题】NodeJS/Mongo:通过各种集合循环查询【英文标题】:NodeJS/Mongo: Looping a query through various collections 【发布时间】:2018-05-04 16:06:11 【问题描述】:我希望使用NodeJS Driver 在 MongoDB 的各种集合中循环查询。 对于这个测试,我使用sample code from the 'findOne' docs 在各种集合中插入一堆文档:
collection.insertMany([a:1, b:1, a:2, b:2, a:3, b:3], w:1, function(err, result)
test.equal(null, err);
同时创建各种集合(每个集合至少有一个先前插入的文档实例):
测试 测试1 测试2 测试3 测试4 测试6 test10我想要的是收集我在数据库中的集合列表(在我的例子中是'test'
):
var MongoClient = require("mongodb").MongoClient,
test = require("assert");
MongoClient.connect("mongodb://localhost:27017/test", function(err, db)
db.listCollections().toArray(function(err, items)
test.ok(items.length >= 1);
console.log(items);
db.close();
);
);
然后弹出前面提到的集合列表。到目前为止一切都很好!我什至可以遍历数组以仅获取集合的名称:
var MongoClient = require("mongodb").MongoClient,
test = require("assert");
MongoClient.connect("mongodb://localhost:27017/test", function(err, db)
db.listCollections().toArray(function(err, items)
test.ok(items.length >= 1);
items.forEach(c =>
console.log(c.name);
);
db.close();
);
);
同样没有问题!但是当我在循环中尝试查询时:
var MongoClient = require("mongodb").MongoClient,
test = require("assert");
MongoClient.connect("mongodb://localhost:27017/test", function(err, db)
db.listCollections().toArray(function(err, items)
test.ok(items.length >= 1);
items.forEach(c =>
var collection = db.collection(c.name);
collection.findOne( a: 2 , fields: b: 1 , function(err, doc)
console.log(doc);
);
);
);
db.close();
);
我明白了:
null
null
null
null
null
null
null
即使循环获取集合似乎工作得很好:
var MongoClient = require("mongodb").MongoClient,
test = require("assert");
MongoClient.connect("mongodb://localhost:27017/test", function(err, db)
db.listCollections().toArray(function(err, items)
test.ok(items.length >= 1);
items.forEach(c =>
var collection = db.collection(c.name);
console.log(collection);
);
);
db.close();
);
示例输出:
Collection
s:
pkFactory:
[Function: ObjectID]
index: 10866728,
createPk: [Function: createPk],
createFromTime: [Function: createFromTime],
createFromHexString: [Function: createFromHexString],
isValid: [Function: isValid],
ObjectID: [Circular],
ObjectId: [Circular] ,
db:
Db
domain: null,
_events: ,
_eventsCount: 0,
_maxListeners: undefined,
s: [Object],
serverConfig: [Getter],
bufferMaxEntries: [Getter],
databaseName: [Getter] ,
topology:
Server
domain: null,
_events: [Object],
_eventsCount: 8,
_maxListeners: undefined,
clientInfo: [Object],
s: [Object] ,
dbName: 'test',
options:
promiseLibrary: [Function: Promise],
readConcern: undefined,
readPreference: [Object] ,
namespace: 'test.test2',
readPreference:
ReadPreference
_type: 'ReadPreference',
mode: 'primary',
tags: undefined,
options: undefined ,
slaveOk: true,
serializeFunctions: undefined,
raw: undefined,
promoteLongs: undefined,
promoteValues: undefined,
promoteBuffers: undefined,
internalHint: null,
collectionHint: null,
name: 'test2',
promiseLibrary: [Function: Promise],
readConcern: undefined
我猜Collection
结构是我的循环的问题,但我不确定到底发生了什么......
这是每个集合的预期输出示例:
_id: 5a13de85a55e615235f71528, b: 2
任何帮助将不胜感激!提前致谢!
【问题讨论】:
【参考方案1】:javascript 中的 ForEach 循环是同步的,直到它不包含任何异步调用。在这种情况下,您不能在 for 循环中调用任何数据库调用。
相反,您可以使用一个名为 async 的库,它带有一些很棒的功能来解决这个问题,如下所示
var MongoClient = require("mongodb").MongoClient,
test = require("assert"),
async = require('async');
MongoClient.connect("mongodb://localhost:27017/test", function (err, db)
db.listCollections().toArray(function (err, items)
test.ok(items.length >= 1);
async.map(items, (each, callback) =>
let collection = db.collection(each.name);
collection.findOne(a: 2, fields: b: 1, function (err, doc)
console.log(doc);
callback();
);
, (err) =>
console.log("done");
);
);
db.close();
);
【讨论】:
嘿罗汉!感谢您的回答,我仍然得到 null,null,null,...,虽然完成了。 没有其他尝试? :P 嘿 Ardzil,你能使用 collection.findOne(a: 2, b: 1, function (err, doc) console.log(doc); callback(); ); 嘿罗汉!感谢您的跟进!仍然得到空,空,空,...,完成。我已经用参数 (collection
) 作为字符串测试了findOne
,它可以工作 _id: 5a13de811c0c39521bfae232, b: 2
所以我不认为它来自查询本身......【参考方案2】:
虽然不是最好的语法并且除了记录输出之外没用,但这对我有用:
var mongodb = require('mongodb');
mongodb.connect('mongodb://localhost:27017/test', function (err, db)
if (err)
throw err;
db.listCollections().toArray(function (err, cols)
if (err)
throw err;
cols.forEach(function (col)
db.collection(col.name).find(, , 0, 1, function (err, docs)
if(err)
throw err;
console.log(col);
docs.forEach(console.log);
);
);
)
)
那么,也许查询条件不匹配?
另外,使用 Promises 会更好:
const mongodb = require('mongodb');
const Promise = require('bluebird');
function getDb()
return Promise.resolve(mongodb.connect('mongodb://localhost:27017/test'));
function getCollections(db)
return Promise.resolve(db.listCollections().toArray());
function getDocs(db, col)
return Promise.resolve(db.collection(col.name).find(,,0,1).toArray());
const data = ;
getDb()
.then((db) =>
data.db = db;
return getCollections(db);
).then((cols) =>
data.cols = cols;
return Promise.map(cols, (col) => getDocs(data.db,col));
).then((docs) =>
console.log(docs);
)
【讨论】:
嘿,SD!我尚未完全测试您的解决方案,但输出似乎正确!谢谢你的帮助! :P 嘿,S.D.!您得到了部分答案...我的意思是您的代码非常适合查找,当我尝试查找 findOne 时,我得到TypeError: docs.forEach is not a function
真的我不明白为什么我在一个没有的函数上得到一个 TypeError甚至没有被修改...? :S
@Ardzii findOne 不返回数组,而是返回单个文档。因此,单个文档不需要 for each。
嘿,SD!感谢您的跟进!我很抱歉我的noobiness和缺乏关注。确实在 docs.forEach 而不是 cols.forEach 上调用了错误,正如我之前理解的那样......以上是关于NodeJS/Mongo:通过各种集合循环查询的主要内容,如果未能解决你的问题,请参考以下文章