mongodb 커서 위에 연속적으로 반복(다음 문서로 이동하기 전에 콜백을 대기)
mongoskin을 사용하여 다음과 같은 쿼리를 수행할 수 있습니다. 그러면 커서가 반환됩니다.
myCollection.find({}, function(err, resultCursor) {
resultCursor.each(function(err, result) {
}
}
그러나 각 문서에 대해 몇 가지 비동기 함수를 호출하고 이 함수가 호출된 후에 커서의 다음 항목으로 이동합니다(비동기.js 모듈의 각 시리즈 구조와 유사).예:
myCollection.find({}, function(err, resultCursor) {
resultCursor.each(function(err, result) {
externalAsyncFunction(result, function(err) {
//externalAsyncFunction completed - now want to move to next doc
});
}
}
내가 어떻게 이럴 수 있지?
감사해요.
갱신:
싶다toArray()이는 대규모 배치 작업이기 때문에 한 번에 결과가 메모리에 맞지 않을 수 있습니다.
.async/await:
const cursor = db.collection("foo").find({});
while(await cursor.hasNext()) {
const doc = await cursor.next();
// process doc here
}
주의:
- 이것은 비동기 반복기가 도착했을 때 훨씬 더 쉽게 수행할 수 있습니다.
- 오류 확인을 위해 try/catch를 추가할 수 있습니다.
- 는
async그렇지 않으면 코드를 로 감싸야 합니다.(async function() { ... })()「」를 하고 있기 에,await. - 에 따라서, 「」를 합니다.
await new Promise(resolve => setTimeout(resolve, 1000));에 (가되는 것을
toArray를 사용하여 모든 결과를 메모리에 로드하지 않으려면 다음과 같은 방법으로 커서를 사용하여 반복할 수 있습니다.
myCollection.find({}, function(err, resultCursor) {
function processItem(err, item) {
if(item === null) {
return; // All done!
}
externalAsyncFunction(item, function(err) {
resultCursor.nextObject(processItem);
});
}
resultCursor.nextObject(processItem);
}
node.disc v10.3에서는 비동기식 반복기를 사용할 수 있습니다.
const cursor = db.collection('foo').find({});
for await (const doc of cursor) {
// do your thing
// you can even use `await myAsyncOperation()` here
}
Jake Archibald는 비동기 반복자에 대한 훌륭한 블로그 글을 썼는데, @user993683의 답변을 읽고 알게 되었습니다.
이는 setImediate를 사용하여 대규모 데이터 집합에서 작동합니다.
var cursor = collection.find({filter...}).cursor();
cursor.nextObject(function fn(err, item) {
if (err || !item) return;
setImmediate(fnAction, item, arg1, arg2, function() {
cursor.nextObject(fn);
});
});
function fnAction(item, arg1, arg2, callback) {
// Here you can do whatever you want to do with your item.
return callback();
}
을 사용하는 것이 ) (nextObject의 콜백을 사용하는 것이 아니라) Promise의 경우, Promise는 다음과 같습니다.노드 v4.2.2의 mongo v2.1.7의 mongo.입니다.Cursor.forEach():
function forEachSeries(cursor, iterator) {
return new Promise(function(resolve, reject) {
var count = 0;
function processDoc(doc) {
if (doc != null) {
count++;
return iterator(doc).then(function() {
return cursor.next().then(processDoc);
});
} else {
resolve(count);
}
}
cursor.next().then(processDoc);
});
}
이를 사용하려면 커서 및 각 문서에서 비동기적으로 작동하는 반복기를 전달하십시오(Cursor.ForEach에서처럼).대부분의 mongodb 네이티브 드라이버 기능처럼 반복기는 약속을 반환해야 합니다.
를 들어, 모든 .test 됩니다 이치노
var theDb;
MongoClient.connect(dbUrl).then(function(db) {
theDb = db; // save it, we'll need to close the connection when done.
var cur = db.collection('test').find();
return forEachSeries(cur, function(doc) { // this is the iterator
return db.collection('test').updateOne(
{_id: doc._id},
{$set: {updated: true}} // or whatever else you need to change
);
// updateOne returns a promise, if not supplied a callback. Just return it.
});
})
.then(function(count) {
console.log("All Done. Processed", count, "records");
theDb.close();
})
비동기 lib를 사용하여 이와 같은 작업을 수행할 수 있습니다.여기서 중요한 것은 현재 문서가 null인지 확인하는 것입니다.만약 그렇다면, 그것은 당신이 끝났다는 뜻입니다.
async.series([
function (cb) {
cursor.each(function (err, doc) {
if (err) {
cb(err);
} else if (doc === null) {
cb();
} else {
console.log(doc);
array.push(doc);
}
});
}
], function (err) {
callback(err, array);
});
장래를 생각할 수 있습니다.
myCollection.find({}, function(err, resultCursor) {
resultCursor.count(Meteor.bindEnvironment(function(err,count){
for(var i=0;i<count;i++)
{
var itemFuture=new Future();
resultCursor.nextObject(function(err,item)){
itemFuture.result(item);
}
var item=itemFuture.wait();
//do what you want with the item,
//and continue with the loop if so
}
}));
});
결과는 '아예'에서 수 .Array재귀함수 같은 걸 사용해서 반복하는 거죠.
myCollection.find({}).toArray(function (err, items) {
var count = items.length;
var fn = function () {
externalAsyncFuntion(items[count], function () {
count -= 1;
if (count) fn();
})
}
fn();
});
편집:
이는 작은 데이터 집합에만 해당되며, 큰 데이터 집합의 경우 다른 답변에서 언급한 것처럼 커서를 사용해야 합니다.
단순한 set Time을 사용할 수 있습니다.Out. 다음은 nodejs에서 실행되는 typescript의 예입니다('when' 모듈을 통해 약속을 사용하지만 약속 없이도 약속을 수행할 수 있습니다).
import mongodb = require("mongodb");
var dbServer = new mongodb.Server('localhost', 27017, {auto_reconnect: true}, {});
var db = new mongodb.Db('myDb', dbServer);
var util = require('util');
var when = require('when'); //npm install when
var dbDefer = when.defer();
db.open(function() {
console.log('db opened...');
dbDefer.resolve(db);
});
dbDefer.promise.then(function(db : mongodb.Db){
db.collection('myCollection', function (error, dataCol){
if(error) {
console.error(error); return;
}
var doneReading = when.defer();
var processOneRecordAsync = function(record) : When.Promise{
var result = when.defer();
setTimeout (function() {
//simulate a variable-length operation
console.log(util.inspect(record));
result.resolve('record processed');
}, Math.random()*5);
return result.promise;
}
var runCursor = function (cursor : MongoCursor){
cursor.next(function(error : any, record : any){
if (error){
console.log('an error occurred: ' + error);
return;
}
if (record){
processOneRecordAsync(record).then(function(r){
setTimeout(function() {runCursor(cursor)}, 1);
});
}
else{
//cursor up
doneReading.resolve('done reading data.');
}
});
}
dataCol.find({}, function(error, cursor : MongoCursor){
if (!error)
{
setTimeout(function() {runCursor(cursor)}, 1);
}
});
doneReading.promise.then(function(message : string){
//message='done reading data'
console.log(message);
});
});
});
언급URL : https://stackoverflow.com/questions/18119387/iterating-over-a-mongodb-cursor-serially-waiting-for-callbacks-before-moving-to
'programing' 카테고리의 다른 글
| WordPress에서 프로그래밍 방식으로 게시물을 만드는 방법 (0) | 2023.04.05 |
|---|---|
| 데이터베이스 내의 모든 스키마를 나열하기 위한 Oracle SQL 쿼리 (0) | 2023.04.05 |
| JSX에서 부울 값을 렌더링할 수 없습니까? (0) | 2023.04.05 |
| AngularJS/Angular-ui-bootstrap datePicker에서 사용되는 언어 변경 (0) | 2023.04.05 |
| AngularJS 오류: '인수 'FirstCtrl'이(가) 함수가 아니며 정의되지 않았습니다. (0) | 2023.04.05 |