Две години по-късно този въпрос просто изскочи в моя 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):
- [ {}, ... ]
- [ {userId:userN._id}, ... ]
- [ {userId:userN._id, channelId: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