2014-09-09 4 views
1

У меня есть следующие модели в моем приложении Sailsjs с многие-ко-многим:Добавить несколько записей в коллекции модели Sailsjs

event.js:

attributes: { 
title : { type: 'string', required: true }, 
description : { type: 'string', required: true }, 
location : { type: 'string', required: true }, 
maxMembers : { type: 'integer', required: true }, 
currentMembers : { collection: 'user', via: 'eventsAttending', dominant: true }, 
creator : { model: 'user', required: true }, 
invitations : { collection: 'invitation', via: 'eventID' }, 
tags : { collection: 'tag', via: 'taggedEvents', dominant: true }, 
lat : { type: 'float' }, 
lon : { type: 'float' }, 
}, 

tags.js:

attributes: { 
tagName : { type: 'string', unique: true, required: true }, 
taggedEvents : { collection: 'event', via: 'tags' }, 
}, 

Основываясь на документации, это соотношение выглядит правильно. У меня есть следующий метод в tag.js, который принимает массив строк тегов и идентификатор события, и предполагается, что добавить или удалить тег, которые были переданы в:

modifyTags: function (tags, eventId) { 
var tagRecords = []; 

_.forEach(tags, function(tag) { 
    Tag.findOrCreate({tagName: tag}, {tagName: tag}, function (error, result) { 
     tagRecords.push({id: result.id}) 
    }) 
}) 

Event.findOneById(eventId).populate('tags').exec(function(error, event){ 
    console.log(event) 
    var currentTags = event.tags; 
    console.log(currentTags) 
    delete currentTags.add; 
    delete currentTags.remove; 

    if (currentTags.length > 0) { 
     currentTags = _.pluck(currentTags, 'id'); 
    } 

    var modifiedTags = _.pluck(tagRecords, 'id'); 
    var tagsToAdd = _.difference(modifiedTags, currentTags); 
    var tagsToRemove = _.difference(currentTags, modifiedTags); 
    console.log('current', currentTags) 
    console.log('remove', tagsToRemove) 
    console.log('add', tagsToAdd) 

    if (tagsToAdd.length > 0) { 
     _.forEach(tagsToAdd, function (tag) { 
     event.tags.add(tag); 
     }) 
     event.save(console.log) 
    } 

    if (tagsToRemove.length > 0) { 
     _.forEach(tagsToRemove, function (tagId) { 
     event.tags.remove(tagId) 
     }) 
     event.save() 
    }  
}) 
} 

Это как называется метод от модели событий:

afterCreate: function(record, next) { 
    Tag.modifyTags(tags, record.id) 
    next(); 
} 

Когда я отправляю к событию/создание, я получаю этот результат: http://pastebin.com/PMiqBbfR.

Похоже, что вызов метода зацикливается, а не только тегиToAdd или tagsToRemove. Что более смущает то, что в конце, в последнем журнале события, похоже, что у события есть правильные теги. Однако, когда я отправляю сообщение в event/1, массив тегов пуст. Я также попытался сэкономить сразу после каждого .add(), но все равно получаю аналогичные результаты.

В идеале, я хотел бы зациклиться на тегахToAdd и tagsToRemove массивов, изменить их идентификаторы в коллекции модели, а затем вызвать .save() один раз на модели.

Я потратил кучу времени, пытаясь отладить это, поэтому любая помощь будет принята с благодарностью!

ответ

1

Есть несколько проблем с реализацией, но главная проблема в том, что вы лечение некоторых методов, а именно - .save() и .findOrCreate, как синхронных методы, когда они (как и все методы ватерлинии) асинхронных, требующий обратного вызова. Таким образом, вы эффективно запускаете кучу кода параллельно и не дожидаетесь его завершения до возвращения.

Кроме того, поскольку вам кажется, что вы пытаетесь сделать это замените текущими тегами событий с этим новым списком, метод, который вы придумали, немного перепроектирован - вам не нужно используйте event.tags.add и event.tags.remove. Вы можете просто использовать простой старый update.

Таким образом, вы, вероятно, может переписать метод modifyTags как:

modifyTags: function (tags, eventId, mainCb) { 

    // Asynchronously transform the `tags` array into an array of Tag records 
    async.map(tags, function(tag, cb) { 
    // For each tag, find or create a new record. 
    // Since the async.map `cb` argument expects a function with 
    // the standard (error, result) node signature, this will add 
    // the new (or existing) Tag instance to the resulting array. 
    // If an error occurs, async.map will exit early and call the 
    // "done()" function below 
    Tag.findOrCreate({tagName: tag}, {tagName: tag}, cb); 
    }, function done (err, tagRecords) { 
    if (err) {return mainCb(err);} 
    // Update the event with the new tags 
    Event.update({id: eventId}, {tags: tagRecords}).exec(mainCb); 
    }); 

} 

Посмотреть полную документацию для async.maphere.

Если вы хотите, чтобы придерживаться своей реализации с помощью .add и .remove, вы все еще хотите использовать async.map и сделать остальную часть вашей логики в методе done. Вам не нужны два вызова .save; просто запустите все коды .add и .remove, затем сделайте один .save(mainCb), чтобы закончить его.

И я не знаю, что вы пытаетесь достичь, удалив .add и .remove методы из currentTags (который является прямой ссылкой на event.tags), но это не будет работать, и будет просто привести к путанице позже!

+0

Спасибо за помощь. У меня было ощущение, что это связано с асинхронными методами, основанными на том, что я нашел в Интернете. Я все еще очень новичок в асинхронных/синхронных методах и обратных вызовах, и, после принятия вашего предложения, я все еще получаю ошибки и немного смущен. Я задал следующий вопрос здесь: http://stackoverflow.com/questions/25800157/add-multiple-records-to-models-collection-sailsjs-followup – CitizenKen

Смежные вопросы