2017-01-21 10 views
0

データの挿入が成功したことを確認するために、データベース内のアイテムの数を取得しようとしています。私は、これはいくつかの簡単な関数を使用して実装することができます知っている:Node.js | MongoDB count():データの挿入前後のカウントの取得

  1. 挿入
  2. 要約

注CONSOLE.LOG

  • 挿入した後、カウント取得を挿入する前に数えなさい
    dbName.equal(insertSize, result.insertedCount) 
    

    ただし、私はjavascriptを初めて使用しています私は非同期コールバックを実装する必要があると思っているので、これを理解したいと思いました。

    挿入機能

    var insertMany = function() { 
    
        // get initial count 
        var count1 = getDbCount(); 
    
        // Insert new 'data' 
        MongoClient.connect(url, function(err, db) { 
         var col = db.collection(collectionName); 
         col.insert(data, {w:1}, function(err,result) {}); 
         db.close(); 
        }); 
    
        /** This needs to be implemented through next/callback 
         after the insert operation **/ 
        var count2 = getDbCount(); 
    
        /** These final console logs should be executed after all 
         other operations are completed **/  
        console.log('[Count] Start: ' + count1 + ' | End:' +count2); 
        console.log('[Insert] Expected: ' + data.length + ' | Actual: ' + (count2 - count1)); 
    
    }; 
    

    は、必要な操作が完了する前にリターンが発生しているので、私はエラーを取得しています

    var getDbCount = function() { 
        MongoClient.connect(url, function(err, db) { 
         if (err) console.log(err); 
    
         var col = db.collection(collectionName); 
    
         col.count({}, function(err, count) { 
          if (err) console.log(err); 
          db.close(); 
          console.log('docs count: ' + count); 
          // This log works fine 
         }); 
    
        }); 
    
        return count; // this is returning as undefined since this is 
            // executing before the count operation is completed 
    }; 
    

    DBカウント機能を取得します。

    ありがとうございました。


    [EDIT]同様にgetCount機能約束

    と私は開始と同様にgetCount機能への約束を追加しました:

    var getCount = function() { 
    
        var dbCount = 0; 
    
        var promise = new Promise(function(resolve, reject) { 
    
         MongoClient.connect(url, function(err, db) { 
    
          if (err) { 
           console.log('Unable to connect to server', err); 
          } else { 
           console.log('Database connection established:' + dbName); 
          } 
    
          // Get the collection 
          var col = db.collection(collectionName); 
    
          col.count({}, function(err, count) { 
           if (err) console.log(err); 
           db.close(); 
           console.log('docs count: ' + count); 
           resolve(null); 
           dbCount = count; 
          }); 
    
         }); 
    
        }); 
    
        promise.then(function() { 
         return dbCount; 
        }); 
    
    }; 
    
    console.log(getCount()); 
    

    は、出力はまだです: 未定義 データベース接続確立された:testdb ドキュメント数:500

    それから、({return count})コードはpromise {db.count()}の前に実行されています。データベース操作が完了する前にundefinedを返します。

    +0

    あなたが試したことを表示しないと間違ったことを伝えるのはちょっと難しいことです。エラーには、エラーが発生した行に関する情報が必要です。エラーが発生したコードブロックと少なくとも呼び出された部分を提供してください – newBee

    +0

    こんにちはnewBee、私はそれを取り上げました。私はコールバックを使って実装することに多くの進歩を遂げていませんでした。なぜならそれが含まれていなかったからです。進歩したら、新しいコードを更新して追加します。ありがとう – carlolm

    +0

    @ CarloP.LasMarias決して 'setTimeout'に決めるべきではありません。特にバックエンドには機能の残虐行為を説明する記事がたくさんあります。プロミスはそのような条件を処理するために開発されたモジュールであり、それがうまくいかない場合、問題はどこかにあるコード内にあります。 Async.jsは 'setTimeout'よりはるかに優れたオプションです。 –

    答えて

    2

    一般的に問題は、関数が返ってきたときに値が既に存在することが予想されることです。非同期関数の場合は、そうでない場合がよくあります。非同期処理に関する膨大な情報があります(Javaのような並列処理と誤解されることはありません)。私はあなたの状況に合わせなければならない例を作成しました

    https://jsfiddle.net/rh3gx76x/1/

    var dummyCount = 5 
    getCount = function() { 
        return new Promise(function(resolve, reject) { 
         setTimeout(function() { // this would be your db call, counting your documents 
          resolve(dummyCount); // dummy for number of documents found 
         }, 100 * Math.random()); 
        }); 
    }; 
    
    insertMany = function() { 
        return new Promise(function(resolve, reject) { 
         setTimeout(function() { // this would be your db call, writing your documents 
          dummyCount += 2; 
          resolve(); 
         }, 100 * Math.random()); 
        }); 
    }; 
    
    runIt = function(callback) { 
        var count1; 
        getCount().then(function(count) { 
         console.log("First callback with value ", count); 
         count1 = count; 
         insertMany().then(function() { 
         getCount().then(function(count2){ 
          console.log("Second callback with value ", count2); 
           callback(null, count1, count2); 
         }); 
         }) 
        }) 
    } 
    
    runIt(function(err, count1, count2) { 
        console.log("count1: " + count1 + ", count2: " + count2); 
    }); 
    

    最後に一つ。 「非同期」パッケージをチェックアウトすることができます。これは、多くのヘルパー関数と制御フローを提供する問題で多くの助けになります。

    +0

    'setTimeout'はひどい習慣です。 I/Oタスクで特にタイムアウトを使用することは推奨されません。無作為にコードを遅らせることによって、時間のシフトを食べています。これは複雑なウェブサイトを開発しながらあなたのリソースを食べるでしょう。 –

    +0

    恐ろしい感謝@newBee、これは今働いています。 – carlolm

    +0

    @Ritik Saxenaここでのタイムアウトは、サンプルを読みやすくする元のポスターを呼び出したdbの代わりとなります。あなたに言及していないリソースの問題について、あなたの後を追うことはできません。次のイベント・ループ・ティックにコードを遅らせることは珍しいことではありません。しかし、あなたは常に "0"のタイムアウトを使用します。 – newBee

    0

    操作が完了する前にリターンが発生しているのは、javacriptから継承されたnodejsのasynchronousデザインです。 Mongoose.connect()からのコールバックは、プログラムが前進して、returnに遭遇している間、操作を行うために残されます。

    エラーステートメントにあなたの問題を解決した回避策を提供していないため、ここで何が間違っているのかについてはコメントできません。しかし、あなたが始めたものを終わらせるための最初の努力を考えれば、Mongoose.connect()が完了してからreturnステートメントが実行されるようにする最良の方法は、JavaScriptのpromiseを使用することです。約束を使用すると、Mongoose.connect()が実行され、コントロールをreturn文に渡します。

    挿入機能

    var insertMany = function() { 
    
    // get initial count 
    var count1 = getDbCount(); 
    
    // Insert new 'data' 
    var promise = new Promise(
        function(resolve,reject){ 
         MongoClient.connect(url, function(err, db) { 
         var col = db.collection(collectionName); 
         col.insert(data, {w:1}, function(err,result) {}); 
         db.close(); 
         resolve(null); 
         }); 
        } 
    ); 
        promise.then(function(val){  
        var count2 = getDbCount(); 
    
        /** These final console logs should be executed after all 
        other operations are completed **/ 
        console.log('[Count] Start: ' + count1 + ' | End:' +count2); 
        console.log('[Insert] Expected: ' + data.length + ' | Actual: ' + (count2 - count1)); 
    }); 
    

    同様に、あなたはGetDB機能に約束を追加することができます

    あなたのコードは次のようになります。 約束の実行中にキーポイントは次のとおり

    1. then()が約束を実行した後に同期して実行される機能の一部を含みます。これはresolveによって呼び出され、渡されたパラメータは関数のコールバックcatchで受信されます。
    2. catch()には、約束事でエラーが発生したときに呼び出される関数の部分が含まれています。これはrejectによって呼び出され、渡されたパラメータはcatch関数のコールバックで受信されます。

    EDIT:約束の代替は、それが約束とは異なり、外部モジュールであるという事実が異なる、async.jsです。

    +0

    このコードは引き続き失敗することに注意してください。 count2は "undefined"という値を持ちます – newBee

    +0

    @newBee書いたコードの後に​​、私は 'GetDB'もこのようにして実行しなければならないと述べました。その後、カウントはcount2に戻る値を持ちます。 –

    +0

    ありがとう@RitikSaxena、私はこれを試みたが、同じエラーが発生しています。約束を追加した後でさえ、その約束は約束の前に実行されています。私は改訂されたgetCountの上に追加しました。 – carlolm

    関連する問題