nodejs: функция сохранения в цикле for, асинхронные проблемы - PullRequest
2 голосов
/ 16 марта 2012

NodeJS + Express, MongoDB + Mongoose

У меня есть фид JSON, где у каждой записи есть набор атрибутов "место встречи" (такие вещи, как "название места", "место встречи", "телефон места встречи" и т. Д.).Я хочу создать коллекцию всех мест в фиде - один экземпляр каждого места, без дупликов.

Я перебираю JSON и проверяю, существует ли место в моей коллекции мест.Если это не так, сохраните его.

jsonObj.events.forEach(function(element, index, array){
    Venue.findOne({'name': element.vname}, function(err,doc){
        if(doc == null){
            var instance = new Venue();
            instance.name = element.vname;
            instance.location = element.location;
            instance.phone = element.vphone;
            instance.save();
        }
    }
}

Желаемый: список всех мест (без дупликов).

Результат: Множество дупов в коллекции мест.

По сути, цикл создал новую запись Venue для каждой записи в фиде JSON.

Я изучаю Node и его асинхронные качества, поэтому я считаю, что цикл for завершается еще до первогоФункция save () завершается, поэтому оператор if всегда проверяет пустую коллекцию.Console.logging поддерживает это утверждение.

Я не уверен, как переработать это так, чтобы оно выполняло желаемую задачу.Я попробовал асинхронный модуль Колана, но не могу помочь.Есть хороший шанс, что я использую неправильно.

Большое спасибо за то, что указали мне правильное направление - я искал безрезультатно.Если асинхронный модуль является правильным ответом, я буду признателен за помощь в его реализации в этом конкретном случае.

Еще раз спасибо!

Ответы [ 2 ]

2 голосов
/ 16 марта 2012

Почему бы не пойти другим путем?Вы не сказали, каков ваш уровень персистентности, но он выглядит как мангуст или, возможно, FastLegSВ любом случае вы можете создать уникальный индекс в поле «Имя».Затем вы можете просто попытаться сохранить что-нибудь и обработать ошибку, если это нарушение уникального индекса.

1 голос
/ 16 марта 2012

Что бы вы ни делали, вы должны делать то, что предлагает @Paul, и создать уникальный индекс в базе данных. Это единственный способ обеспечить уникальность.

Но основная проблема с вашим кодом заключается в том, что при вызове instance.save () вам необходим обратный вызов, который запускает следующую итерацию, иначе у базы данных не будет времени для сохранения новой записи. Это состояние гонки. Вы можете решить эту проблему с помощью функции forEachSeries caolan.

В качестве альтернативы, вы можете получить массив записей уже в коллекции Venue, которые соответствуют элементу в вашем объекте JSON, затем отфильтровать совпадения из объекта, а затем итеративно добавить каждый элемент, оставшийся в фильтрованном объекте JSON. Это сведет к минимуму количество операций с базой данных, поскольку не будет пытаться создавать дубликаты.

Venue.find({'name': { $in: jsonObj.events.map(function(event){ return event.vname; }) }}, function (err, docs){
  var existingVnames = docs.map(function(doc){ return doc.name; });
  var filteredEvents = jsonObj.events.filter(function(event){
    return existingVnames.indexOf(event.vname) === -1;
  });
  filteredEvents.forEach(function(event){
    var venue = new Venue();
    venue.name = event.vname;
    venue.location = event.location;
    venue.phone = event.vphone;
    venue.save(function (err){
      // Optionally, do some logging here, perhaps.
      if (err) return console.error('Something went wrong!');
      else return console.log('Successfully created new venue %s', venue.name);
    });
  });
});
...