Нахождение длины коллекции в базе данных - PullRequest
0 голосов
/ 14 ноября 2018

У меня в базе данных реального времени Firebase более 20 тыс. Объектов.Теперь мне нужно вынуть все эти объекты и сделать что-нибудь с ними.Проблема в том, что серверу не хватает памяти каждый раз, когда я это делаю.Это мой текущий код:

sendEmail.get('/:types/:message', cors(), async (req, res, next) => {
    console.log(5);
    const types = JSON.parse(req.params.types);
    console.log('types', types);
    let recipients = [];
    let mails = [];
    if (types.includes('students')) {
        console.log(1);
        const tmpUsers = await admin.database().ref('Users').orderByChild('student').equalTo(true).once('value').then(r => r.val()).catch(e => console.log(e));
        recipients = recipients.concat(tmpUsers);
    }
    if (types.includes('solvers')) {
        console.log(2);
        let tmpUsers = await admin.database().ref('Users').orderByChild('userType').equalTo('person').once('value').then(r => r.val()).catch(e => console.log(e));
        tmpUsers = tmpUsers.concat(arrayFromObject(await admin.database().ref('Users').orderByChild('userType').equalTo('company').once('value').then(r => r.val()).catch(e => console.log(e))));
        recipients = recipients.concat(tmpUsers);
    }
});

Так что у меня есть два варианта.Потоковая передача или ограничение ответа с помощью startAt и endAt.Но чтобы ограничить ответы, мне нужно знать, сколько именно объектов у меня есть.И для этого мне нужно скачать всю коллекцию ... Теперь вы видите мою проблему.Как я могу узнать, сколько документов у меня есть, не загружая всю коллекцию?

Ответы [ 2 ]

0 голосов
/ 14 ноября 2018

Вам не нужно знать размер коллекции, чтобы обрабатывать их партиями.

Вы можете сделать это, упорядочив их по ключу, ограничив до 1000 или около того, а затем при следующей партии запустите последний ключ первой партии.

Если вы все еще хотите узнать, как получить размер коллекции, единственный хороший способ - сохранить размер коллекции в отдельном узле и обновлять ее при обновлении коллекции.

0 голосов
/ 14 ноября 2018

Вы можете попробовать разбить запрос на страницы, комбинируя 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, чтобы освободить ресурсы, а затем перейти к следующему пакету.Это полностью зависит от того, какие действия вам нужно выполнить над объектами, и вам нужно будет взвесить, действительно ли необходимо обрабатывать (и хранить в памяти) весь набор результатов за один раз.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...