【问题标题】:NodeJS/Mongo: Looping a query through various collectionsNodeJS/Mongo:通过各种集合循环查询
【发布时间】: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 }

任何帮助将不胜感激!提前致谢!

【问题讨论】:

    标签: node.js database mongodb collections documents


    【解决方案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 上调用了错误,正如我之前理解的那样......
    猜你喜欢
    • 2019-01-18
    • 2017-06-15
    • 2014-10-22
    • 2023-03-22
    • 2017-05-31
    • 1970-01-01
    • 1970-01-01
    • 2012-11-03
    • 2014-12-20
    相关资源
    最近更新 更多