Вы можете попробовать разбить запрос на страницы, комбинируя limitToFirst
/ limitToLast
и startAt
/ endAt
.
Например, первый запрос можно выполнить с помощью limitToFirst(1000)
, затем получите последний ключ из этого возвращенного списка и используйте его с startAt(key)
и другим limitToFirst(1000)
, повторяя, пока не достигнете конца коллекции.
В node.js он может выглядеть как-товот так ( непроверенный код ):
let recipients = [];
let tmpUsers = next();
recipients = filter(recipients, tmpUsers);
// startAt is inclusive, so when this reaches the last result there will only be 1
while (tmpUsers.length>1) {
let lastKey = tmpUsers.slice(-1).pop().key;
tmpUsers = next(lastKey);
if (tmpUsers.length>1) { // Avoid duplicating last result
recipients = filter(recipients, tmpUsers);
}
}
async function next(startAt) {
if (!startAt) {
return await admin.database().ref('Users')
.orderByKey()
.limitToFirst(1000)
.once('value').then(r => r.val()).catch(e => console.log(e));
} else {
return await admin.database().ref('Users')
.orderByKey()
.startAt(startAt)
.limitToFirst(1000)
.once('value').then(r => r.val()).catch(e => console.log(e));
}
}
function filter(array1, array2) {
// TODO: Filter the results here as we can't combine orderByChild/orderByKey
return array1.concat(array2);
}
Проблема в том, что вы не сможете использовать фильтрацию на стороне базы данных, поэтому вам нужно будет отфильтровать результатывручную, что может ухудшить ситуацию, в зависимости от того, сколько элементов нужно хранить в переменной recipients
за один раз.
Другой вариант - обрабатывать их партиями (например, 1000), popих из массива recipients
, чтобы освободить ресурсы, а затем перейти к следующему пакету.Это полностью зависит от того, какие действия вам нужно выполнить над объектами, и вам нужно будет взвесить, действительно ли необходимо обрабатывать (и хранить в памяти) весь набор результатов за один раз.