Спустя два года этот вопрос как раз всплыл в моем RSS-клиенте...
С мая 2012 года ситуация несколько изменилась, и теперь мы можем решить эту проблему другим способом. В частности, сообщество Javascript стало «осведомленным о сокращении» после принятия решения о включении Array.prototype.reduce
(и других методов Array) в ECMAScript5. Array.prototype.reduce
всегда был (и до сих пор) доступен в виде полифилла, но в то время многие из нас мало ценили его. Те, кто бежал на опережение, могут, конечно, возразить по этому поводу.
Проблема, поставленная в вопросе, кажется шаблонной, со следующими правилами:
- The objects in the array passed as the first param to
conn.collection(table).insert()
build as follows (where N
corresponds to the object's index in an array):
- [ {}, ... ]
- [ {ID_пользователя:userN._id}, ...]
- [ {ID_пользователя:userN._id, идентификатор канала:channelN._id}, ...]
- имена таблиц (по порядку):
users
, channels
, articles
.
- соответствующие свойства объекта:
user
, channel
, article
(т. е. имена таблиц без множественного числа 's').
Общий шаблон из этой статьи 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
});
Это хорошо работает, потому что все таблицы в вопросе имеют регулярное множественное число (пользователь => пользователи, канал => каналы). Если бы какой-либо из них был неправильным (например, стимул => стимулы, ребенок => дети), то нам нужно было бы переосмыслить - (и, возможно, реализовать хэш поиска). В любом случае, адаптация будет довольно тривиальной.
person
Roamer-1888
schedule
14.04.2014