У меня есть два типа документов, листинг и продукты. Листингового объект содержит список продуктов для определенных стран, например:Извлечение нескольких документов в хранимой процедуре (Azure DocumentDB)
Листинг:
{
"Name": "Default",
"Countries": {
"_default": [
"4QlxAPFcCAAPAAAAAAAAAA==",
"4QlxAPFcCAAHAAAAAAAAAA=="
],
"US": [
"4QlxAPFcCAAIAAAAAAAAAA==",
"4QlxAPFcCAAHAAAAAAAAAA=="
]
},
"Type": "Listing",
"id": "dfed1839-07c5-482b-81c5-669b1dbcd0b6",
"_rid": "4QlxAPFcCAAEAAAAAAAAAA=="
}
продукта:
{
"Name": "Widget",
"Price": 3.45,
"Type": "Product",
"_rid": "4QlxAPFcCAAHAAAAAAAAAA=="
}
Моя цель состояла в том, чтобы создать хранимую процедуру в коллекции Azure DocumentDB с двумя параметрами, rid
и country
, которые по существу доставит листинговый документ и документы для этой страны наиболее эффективным образом. Моя презумпция заключается в том, что загрузка документа по его идентификатору ресурса с использованием getContext().getCollection().readDocument(...)
будет самым быстрым способом, поэтому попытка создать для этого хранимую процедуру.
Мои попытки были связаны с последовательными вызовами (callback hell?), Используя генератор/итераторы с выходом, а затем с использованием чистого метода Promise
. Все попытки дали тот же результат:
Он доставит первый документ, но закончится довольно внезапно после того, как документ был получен.
Для справки, вот моя последняя попытка:
function test(rid, country) {
var collection = getContext().getCollection();
var collectionSelfLink = collection.getSelfLink();
var docsLink = collectionSelfLink + "docs/";
var body = getContext().getResponse().setBody;
function getDocument(rid) {
return new Promise(function(resolve, reject) {
var accepted = collection.readDocument(docsLink + rid, (err, doc, opts) => {
resolve(doc);
});
if (!accepted)
reject("Not accepted");
});
}
getDocument(rid)
.then(doc => {
body("0. First step"); // set test body
// Countries is a Dictionary<string, string[]> with resource ids
return doc.Countries[country] || doc.Countries["_default"];
})
// This is how far it gets, resulting in response "1. Documents to fetch: 2"
.then(a => body("1. Documents to fetch: " + a.length))
.then(a => a.map(function(productId) { return getDoument(productId); }))
.then(a => body("2. It should come this far, right?"))
.then(a => Promise.all(a))
.then(a => body(a))
.catch(function(e) { throw new Error(JSON.stringify(e)); });
}
Я не эксперт по обещаниям. Я склонен передавать код своим обратным вызовам или использовать async.js (да, вы можете загрузить его как зависимость внутри sproc), но мне интересно, ваша проблема в строке, которая вызывает 'a.map'. Обертка '. Then' вернет обещание, которое представляет собой набор обещаний с этой точки вперед. Кроме того, вы предпочитаете однолинейные функции в ваших вызовах '.then()', но некоторые из них (вызовы на тело и даже вызов .map могут выполняться в строю. Единственное, что вам действительно нужно для обещания for is async call to readDocument. С другой стороны, это может быть просто стиль программирования обещаний. –
Я пробовал указанную выше цепочку вызовов в REPL с издетой функцией 'getDocument', и это работает. Я также, как уже отмечалось, попытался сделать цикл внутри исходного 'collection.readDocument (...)', и при использовании for-of/for-in/for он завершит половину пути (взяв 2 из 4 элементов, которые у меня были в список) .При использовании '.forEach', он прошел через весь массив, но не дождался, когда вызовы будут выполнены. Мне интересно, как вызывающий определяет, когда« завершать »... –
Насколько велика массив? Как обещает цепочка обещаний ('a.map()') решить, насколько распараллеливается имп lement? Моя новая теория заключается в том, что с циклом for или вашим подходом a.map, вы слишком широко размахиваете и превышаете некоторый ресурс. Возможно, вам придется ограничить распараллеливание подобно методам async.js '... Limit()'. –