2017-02-03 2 views
2

Я пытаюсь выполнить пакетную операцию в базе данных mongo. Идея состояла в том, чтобы перебирать каждого пользователя, а затем находить других пользователей, которые изучают один и тот же курс, или идут в один университет и хранят информацию об этих матчах.Операция NodeJS Batch Mongo, ожидание обратных вызовов

Все содержится в цикле, как это:

User.find({}, function(err, doc){ 
    doc.forEach(function(candidate){ 
     //other find operations in here 
     ... 
    } 
} 

Где «User» является совокупность пользователей, зарегистрированных на сайте. Проблема, с которой я сталкиваюсь, заключается в том, что цикл forEach отправляет все обратные вызовы для каждого пользователя, тогда как я хочу дождаться завершения всех обратных вызовов внутри цикла forEach, прежде чем переходить к следующему документу.

Я пробовал использовать async, но я просто не могу понять это.

Как я могу обрабатывать каждый пользователь по одному за раз?

ответ

1

Вы можете использовать async для этого, например. async.eachSeries:

async.eachSeries(doc, function (candidate, cb) { 
    //other find operations in here 
    ... 
    // and you call cb() once they're done (important!) 
    // or call cb('some error') if it failed 
}, function (err) { 
    if (err) { 
     // this means that some cb() above was called with error 
    } else { 
     // here all candidates are processed successfully 
    } 
}); 

См: https://caolan.github.io/async/docs.html#eachSeries

+0

Спасибо! Используя сочетание async.eachSeries() и async.serial(), сделал трюк. –

0

Один из способов подтолкнуть функции в массив, а затем вызвать их другой способ является использование наблюдаемых, который очень хорошо для цикла асинхронных операций.

var candidatesOps = []; 
User.find({}, function(err, doc){ 
    doc.forEach(function(candidate){ 
    var func =  function(candidate){ 
     //other find operations in here 
     }; 

     candidatesOps.push(func); 

     ... 
    } 
} 

if(candidatesOps){ //call them candidatesOps[0]() } 
0

Эта задача может быть легко сделан без необходимости диспетчерского всех обратных вызовов для каждого пользователя, используйте $lookup трубопровод в общей операции, где вы создаете "self-join" на коллекции пользователей, фильтровать документы, используя $match конвейер для возврата только тех пользователей, которые имеют один и тот же курс с другими пользователями.

Например, следующий будет возвращать все пользователи, которые изучают тот же курс, учитывая есть поле, называемое course:

User.aggregate([ 
    { "$match": { "course": { "$exists": true } } }, 
    { 
     "$lookup": { 
      "from": "users", 
      "localField": "course", 
      "foreignField": "course", 
      "as": "users_courses" 
     } 
    }, 
    { "$match": { "users_courses.1": { "$exists": true } } } 
], callback); 

Тестирование в Монго оболочки

db.test.insert([ 
    { "name": "a", "course": "maths" }, 
    { "name": "b", "course": "english" }, 
    { "name": "c", "course": "maths" }, 
    { "name": "d", "course": "science" }, 
    { "name": "e", "course": "maths" }, 
    { "name": "f", "course": "history" }, 
    { "name": "g", "course": "history" } 
]) 

Эксплуатация агрегатного агрегата

db.test.aggregate([ 
    { "$match": { "course": { "$exists": true } } }, 
    { 
     "$lookup": { 
      "from": "users", 
      "localField": "course", 
      "foreignField": "course", 
      "as": "users_courses" 
     } 
    }, 
    { "$match": { "users_courses.1": { "$exists": true } } } 
]) 

Пример вывода

/* 1 */ 
{ 
    "_id" : ObjectId("58948c0dd04f1bbdbf331ea7"), 
    "name" : "a", 
    "course" : "maths", 
    "users_courses" : [ 
     { 
      "_id" : ObjectId("58948c0dd04f1bbdbf331ea7"), 
      "name" : "a", 
      "course" : "maths" 
     }, 
     { 
      "_id" : ObjectId("58948c0dd04f1bbdbf331ea9"), 
      "name" : "c", 
      "course" : "maths" 
     }, 
     { 
      "_id" : ObjectId("58948c0dd04f1bbdbf331eab"), 
      "name" : "e", 
      "course" : "maths" 
     } 
    ] 
} 

/* 2 */ 
{ 
    "_id" : ObjectId("58948c0dd04f1bbdbf331ea9"), 
    "name" : "c", 
    "course" : "maths", 
    "users_courses" : [ 
     { 
      "_id" : ObjectId("58948c0dd04f1bbdbf331ea7"), 
      "name" : "a", 
      "course" : "maths" 
     }, 
     { 
      "_id" : ObjectId("58948c0dd04f1bbdbf331ea9"), 
      "name" : "c", 
      "course" : "maths" 
     }, 
     { 
      "_id" : ObjectId("58948c0dd04f1bbdbf331eab"), 
      "name" : "e", 
      "course" : "maths" 
     } 
    ] 
} 

/* 3 */ 
{ 
    "_id" : ObjectId("58948c0dd04f1bbdbf331eab"), 
    "name" : "e", 
    "course" : "maths", 
    "users_courses" : [ 
     { 
      "_id" : ObjectId("58948c0dd04f1bbdbf331ea7"), 
      "name" : "a", 
      "course" : "maths" 
     }, 
     { 
      "_id" : ObjectId("58948c0dd04f1bbdbf331ea9"), 
      "name" : "c", 
      "course" : "maths" 
     }, 
     { 
      "_id" : ObjectId("58948c0dd04f1bbdbf331eab"), 
      "name" : "e", 
      "course" : "maths" 
     } 
    ] 
} 

/* 4 */ 
{ 
    "_id" : ObjectId("58948c0dd04f1bbdbf331eac"), 
    "name" : "f", 
    "course" : "history", 
    "users_courses" : [ 
     { 
      "_id" : ObjectId("58948c0dd04f1bbdbf331eac"), 
      "name" : "f", 
      "course" : "history" 
     }, 
     { 
      "_id" : ObjectId("58948c0dd04f1bbdbf331ead"), 
      "name" : "g", 
      "course" : "history" 
     } 
    ] 
} 

/* 5 */ 
{ 
    "_id" : ObjectId("58948c0dd04f1bbdbf331ead"), 
    "name" : "g", 
    "course" : "history", 
    "users_courses" : [ 
     { 
      "_id" : ObjectId("58948c0dd04f1bbdbf331eac"), 
      "name" : "f", 
      "course" : "history" 
     }, 
     { 
      "_id" : ObjectId("58948c0dd04f1bbdbf331ead"), 
      "name" : "g", 
      "course" : "history" 
     } 
    ] 
} 
Смежные вопросы