Два года спустя, этот вопрос просто появился в моем RSS клиент ...
вещи переместились на несколько с мая 2012 года, и мы могли бы выбрать, чтобы решить этот по-другому прямо сейчас. Более конкретно, сообщество Javascript стало «уменьшающим сознание», поскольку решение включить в ECMAScript5 Array.prototype.reduce
(и другие методы Array). Array.prototype.reduce
был всегда (и до сих пор) доступен как полиполк, но в то время он был немного оценен многими из нас. Разумеется, те, кто бежал впереди кривой, могут смириться с этим.
Проблема поставлена в вопросе, как представляется, шаблонными, с правилами следующим образом:
- Объектов в массиве передается в качестве первых паров для
conn.collection(table).insert()
сборки следующим образом (где N
соответствует индексу объекта в массив):
- [{}, ...]
- [{идентификатор пользователя: userN._id}, ...]
- [{идентификатор пользователя: userN._id, channelId: channelN._id}, ...]
- названия таблиц (в порядке):
users
, channels
, articles
.
- соответствующими объектами являются:
user
, channel
, article
(т.е. имена таблиц без плюрализации 's').
Общий шаблон из this article by Taoofcode) для создания асинхронного вызова в серии:
function workMyCollection(arr) {
return arr.reduce(function(promise, item) {
return promise.then(function(result) {
return doSomethingAsyncWithResult(item, result);
});
}, q());
}
С достаточно легкой адаптацией, эта модель может быть сделана, чтобы организовать требуемую последовательность:
function cascadeInsert(tables, n) {
/*
/* tables: array of unpluralisd table names
/* n: number of users to insert.
/* returns promise of completion|error
*/
var ids = []; // this outer array is available to the inner functions (to be read and written to).
for(var i=0; i<n; i++) { ids.push({}); } //initialize the ids array with n plain objects.
return tables.reduce(function (promise, t) {
return promise.then(function (docs) {
for(var i=0; i<ids.length; i++) {
if(!docs[i]) throw (new Error(t + ": returned documents list does not match the request"));//or simply `continue;` to be error tolerant (if acceptable server-side).
ids[i][t+'Id'] = docs[i]._id; //progressively add properties to the `ids` objects
}
return insert(ids, t + 's');
});
}, Q());
}
Наконец, вот работающий по возвращению работник, insert()
:
function insert(ids, t) {
/*
/* ids: array of plain objects with properties as defined by the rules
/* t: table name.
/* returns promise of docs
*/
var dfrd = Q.defer();
conn.collection(t).insert(ids, function(err, docs) {
(err) ? dfrd.reject(err) : dfrd.resolve(docs);
});
return dfrd.promise;
}
Таким образом, вы можете указать в качестве параметров, переданных cascadeInsert
, фактическим именам таблиц/свойств и количеству вставляемых пользователей.
cascadeInsert(['user', 'channel', 'article'], 2).then(function() {
// you get here if everything was successful
}).catch(function (err) {
// you get here if anything failed
});
Это хорошо работает, потому что таблицы в вопросе все регулярные множественные (пользователи => пользователей, канал => каналы). Если какой-либо из них был нерегулярным (например, stimulus => stimuli, child => children), тогда нам нужно было бы переосмыслить - (и, вероятно, реализовать хеш-поиск). В любом случае адаптация была бы довольно тривиальной.
Спасибо, но ... Я не нахожу его более простым, чем оригинал :( – Freewind
У вашего оригинала вообще нет обработки ошибок. – Domenic
Спасибо за демонстрацию ошибок: – Freewind