Можно ли подсчитать, сколько элементов в коллекции, используя новую базу данных Firebase Cloud Firestore?
Если да, то как мне это сделать?
Можно ли подсчитать, сколько элементов в коллекции, используя новую базу данных Firebase Cloud Firestore?
Если да, то как мне это сделать?
Ответы:
Как и на многие вопросы, ответ - это зависит от обстоятельств .
Вы должны быть очень осторожны при работе с большими объемами данных во внешнем интерфейсе. Помимо того, что ваш интерфейс будет вялым, Firestore также взимает с вас 0,60 доллара за миллион прочитанных вами операций.
Используйте с осторожностью - пользовательский интерфейс Frontend может пострадать
Обработка этого на внешнем интерфейсе должна быть прекрасной, если вы не используете слишком много логики с этим возвращаемым массивом.
db.collection('...').get().then(snap => {
size = snap.size // will return the collection size
});
Используйте с осторожностью - вызовы чтения из Firestore могут дорого стоить
Обработка этого во внешнем интерфейсе неосуществима, так как это имеет слишком большой потенциал, чтобы замедлить работу пользовательской системы. Мы должны обрабатывать эту логику на стороне сервера и возвращать только размер.
Недостатком этого метода является то, что вы все еще вызываете чтение из хранилища (равное размеру вашей коллекции), что в конечном итоге может обойтись вам дороже, чем ожидалось.
Облачная функция:
...
db.collection('...').get().then(snap => {
res.status(200).send({length: snap.size});
});
Внешний интерфейс:
yourHttpClient.post(yourCloudFunctionUrl).toPromise().then(snap => {
size = snap.length // will return the collection size
})
Самое масштабируемое решение
FieldValue.increment ()
По состоянию на апрель 2019 года Firestore теперь позволяет увеличивать счетчики полностью атомарно и без предварительного чтения данных . Это гарантирует, что у нас есть правильные значения счетчиков даже при одновременном обновлении из нескольких источников (ранее решалось с использованием транзакций), а также сокращается количество выполняемых нами операций чтения базы данных.
Прослушивая любое удаление или создание документа, мы можем добавить или удалить поле счетчика, которое находится в базе данных.
См. Документацию по firestore - Распределенные счетчики или посмотрите « Агрегирование данных » Джеффа Делани. Его руководства поистине фантастичны для всех, кто использует AngularFire, но его уроки следует перенести и на другие фреймворки.
Облачная функция:
export const documentWriteListener =
functions.firestore.document('collection/{documentUid}')
.onWrite((change, context) => {
if (!change.before.exists) {
// New document Created : add one to count
db.doc(docRef).update({numberOfDocs: FieldValue.increment(1)});
} else if (change.before.exists && change.after.exists) {
// Updating existing document : Do nothing
} else if (!change.after.exists) {
// Deleting document : subtract one from count
db.doc(docRef).update({numberOfDocs: FieldValue.increment(-1)});
}
return;
});
Теперь на веб-интерфейсе вы можете просто запросить это поле numberOfDocs, чтобы получить размер коллекции.
firestore.runTransaction { ... }
блок. Это устраняет проблемы параллелизма при доступе numberOfDocs
.
Самый простой способ сделать это - прочитать размер «querySnapshot».
db.collection("cities").get().then(function(querySnapshot) {
console.log(querySnapshot.size);
});
Вы также можете прочитать длину массива документов внутри querySnapshot.
querySnapshot.docs.length;
Или, если «querySnapshot» пуст, путем чтения пустого значения, которое вернет логическое значение.
querySnapshot.empty;
db.collection.count()
. Думая бросить их только для этого
Насколько я знаю, для этого нет встроенного решения, и прямо сейчас это возможно только в узле sdk. Если у тебя есть
db.collection('someCollection')
ты можешь использовать
.select([fields])
чтобы определить, какое поле вы хотите выбрать. Если вы выполните пустой select (), вы просто получите массив ссылок на документы.
пример:
db.collection('someCollection').select().get().then(
(snapshot) => console.log(snapshot.docs.length)
);
Это решение является оптимизацией только для худшего случая загрузки всех документов и не масштабируется для больших коллекций!
Также взгляните на это:
Как получить количество документов в коллекции с помощью Cloud Firestore
select(['_id'])
быстрее, чемselect()
Будьте осторожны при подсчете количества документов для больших коллекций . Это немного сложно с базой данных firestore, если вы хотите иметь заранее рассчитанный счетчик для каждой коллекции.
Такой код в этом случае не работает:
export const customerCounterListener =
functions.firestore.document('customers/{customerId}')
.onWrite((change, context) => {
// on create
if (!change.before.exists && change.after.exists) {
return firestore
.collection('metadatas')
.doc('customers')
.get()
.then(docSnap =>
docSnap.ref.set({
count: docSnap.data().count + 1
}))
// on delete
} else if (change.before.exists && !change.after.exists) {
return firestore
.collection('metadatas')
.doc('customers')
.get()
.then(docSnap =>
docSnap.ref.set({
count: docSnap.data().count - 1
}))
}
return null;
});
Причина в том, что каждый триггер облачного хранилища должен быть идемпотентным, как сказано в документации хранилища хранилищ: https://firebase.google.com/docs/functions/firestore-events#limitations_and_guarantees
Итак, чтобы предотвратить многократное выполнение вашего кода, вам необходимо управлять событиями и транзакциями. Это мой особый способ работы со счетчиками больших коллекций:
const executeOnce = (change, context, task) => {
const eventRef = firestore.collection('events').doc(context.eventId);
return firestore.runTransaction(t =>
t
.get(eventRef)
.then(docSnap => (docSnap.exists ? null : task(t)))
.then(() => t.set(eventRef, { processed: true }))
);
};
const documentCounter = collectionName => (change, context) =>
executeOnce(change, context, t => {
// on create
if (!change.before.exists && change.after.exists) {
return t
.get(firestore.collection('metadatas')
.doc(collectionName))
.then(docSnap =>
t.set(docSnap.ref, {
count: ((docSnap.data() && docSnap.data().count) || 0) + 1
}));
// on delete
} else if (change.before.exists && !change.after.exists) {
return t
.get(firestore.collection('metadatas')
.doc(collectionName))
.then(docSnap =>
t.set(docSnap.ref, {
count: docSnap.data().count - 1
}));
}
return null;
});
Примеры использования здесь:
/**
* Count documents in articles collection.
*/
exports.articlesCounter = functions.firestore
.document('articles/{id}')
.onWrite(documentCounter('articles'));
/**
* Count documents in customers collection.
*/
exports.customersCounter = functions.firestore
.document('customers/{id}')
.onWrite(documentCounter('customers'));
Как видите, ключом к предотвращению множественного выполнения является свойство с именем eventId в объекте контекста. Если функция обрабатывалась много раз для одного и того же события, идентификатор события будет одинаковым во всех случаях. К сожалению, в вашей базе данных должна быть коллекция «событий».
context.eventId
при многократных вызовах одного и того же триггера всегда будет одинаковым? В моем тестировании он кажется последовательным, но я не могу найти никакой «официальной» документации, подтверждающей это.
В 2020 году этого все еще нет в Firebase SDK, однако он доступен в Firebase Extensions (бета), однако его довольно сложно настроить и использовать ...
Разумный подход
Помощники ... (создание / удаление кажется излишним, но дешевле, чем onUpdate)
export const onCreateCounter = () => async (
change,
context
) => {
const collectionPath = change.ref.parent.path;
const statsDoc = db.doc("counters/" + collectionPath);
const countDoc = {};
countDoc["count"] = admin.firestore.FieldValue.increment(1);
await statsDoc.set(countDoc, { merge: true });
};
export const onDeleteCounter = () => async (
change,
context
) => {
const collectionPath = change.ref.parent.path;
const statsDoc = db.doc("counters/" + collectionPath);
const countDoc = {};
countDoc["count"] = admin.firestore.FieldValue.increment(-1);
await statsDoc.set(countDoc, { merge: true });
};
export interface CounterPath {
watch: string;
name: string;
}
Экспортированные крючки Firestore
export const Counters: CounterPath[] = [
{
name: "count_buildings",
watch: "buildings/{id2}"
},
{
name: "count_buildings_subcollections",
watch: "buildings/{id2}/{id3}/{id4}"
}
];
Counters.forEach(item => {
exports[item.name + '_create'] = functions.firestore
.document(item.watch)
.onCreate(onCreateCounter());
exports[item.name + '_delete'] = functions.firestore
.document(item.watch)
.onDelete(onDeleteCounter());
});
В бою
Строительный кореньБудет отслеживаться коллекция и все вложенные коллекции .
Здесь под /counters/
корневым путем
Теперь количество коллекций будет обновляться автоматически и со временем! Если вам нужен счетчик, просто используйте путь к коллекции с префиксом counters
.
const collectionPath = 'buildings/138faicnjasjoa89/buildingContacts';
const collectionCount = await db
.doc('counters/' + collectionPath)
.get()
.then(snap => snap.get('count'));
Ограничения
Поскольку этот подход использует единую базу данных и документ, он ограничен ограничением Firestore, равным 1 обновлению в секунду для каждого счетчика. В конечном итоге он будет согласованным, но в случаях, когда добавляются / удаляются большие объемы документов, счетчик будет отставать от фактического количества собранных документов.
Я согласен с @Matthew, если вы выполните такой запрос , это будет дорого стоить .
[СОВЕТЫ РАЗРАБОТЧИКАМ ПЕРЕД НАЧАЛОМ ИХ ПРОЕКТОВ]
Поскольку мы предусмотрели эту ситуацию в начале, мы можем фактически создать коллекцию, а именно счетчики с документом, чтобы хранить все счетчики в поле с типом number
.
Например:
Для каждой операции CRUD в коллекции обновите встречный документ:
В следующий раз, когда вы захотите получить номер коллекции, вам просто нужно запросить / указать на поле документа. [1 операция чтения]
Кроме того, вы можете сохранить имя коллекций в массиве, но это будет сложно, состояние массива в firebase показано ниже:
// we send this
['a', 'b', 'c', 'd', 'e']
// Firebase stores this
{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e'}
// since the keys are numeric and sequential,
// if we query the data, we get this
['a', 'b', 'c', 'd', 'e']
// however, if we then delete a, b, and d,
// they are no longer mostly sequential, so
// we do not get back an array
{2: 'c', 4: 'e'}
Итак, если вы не собираетесь удалять коллекцию, вы можете использовать массив для хранения списка имен коллекций вместо того, чтобы каждый раз запрашивать всю коллекцию.
Надеюсь, это поможет!
Нет, в настоящее время нет встроенной поддержки запросов агрегирования. Однако вы можете сделать несколько вещей.
Первый документирован здесь . Вы можете использовать транзакции или облачные функции для хранения совокупной информации:
В этом примере показано, как использовать функцию для отслеживания количества оценок в подколлекции, а также средней оценки.
exports.aggregateRatings = firestore
.document('restaurants/{restId}/ratings/{ratingId}')
.onWrite(event => {
// Get value of the newly added rating
var ratingVal = event.data.get('rating');
// Get a reference to the restaurant
var restRef = db.collection('restaurants').document(event.params.restId);
// Update aggregations in a transaction
return db.transaction(transaction => {
return transaction.get(restRef).then(restDoc => {
// Compute new number of ratings
var newNumRatings = restDoc.data('numRatings') + 1;
// Compute new average rating
var oldRatingTotal = restDoc.data('avgRating') * restDoc.data('numRatings');
var newAvgRating = (oldRatingTotal + ratingVal) / newNumRatings;
// Update restaurant info
return transaction.update(restRef, {
avgRating: newAvgRating,
numRatings: newNumRatings
});
});
});
});
Решение, упомянутое jbb, также полезно, если вы хотите только нечасто подсчитывать документы. Обязательно используйте select()
оператор, чтобы не загружать все документы (это большая пропускная способность, когда вам нужно только подсчет). select()
пока доступен только в серверных SDK, поэтому это решение не будет работать в мобильном приложении.
Увеличьте счетчик с помощью admin.firestore.FieldValue.increment :
exports.onInstanceCreate = functions.firestore.document('projects/{projectId}/instances/{instanceId}')
.onCreate((snap, context) =>
db.collection('projects').doc(context.params.projectId).update({
instanceCount: admin.firestore.FieldValue.increment(1),
})
);
exports.onInstanceDelete = functions.firestore.document('projects/{projectId}/instances/{instanceId}')
.onDelete((snap, context) =>
db.collection('projects').doc(context.params.projectId).update({
instanceCount: admin.firestore.FieldValue.increment(-1),
})
);
В этом примере мы увеличиваем instanceCount
поле в проекте каждый раз, когда документ добавляется во instances
вложенную коллекцию. Если поле еще не существует, оно будет создано и увеличено до 1.
Увеличение является транзакционным внутри, но вы должны использовать распределенный счетчик, если вам нужно увеличивать чаще, чем каждую 1 секунду.
Это часто предпочтительнее осуществлять onCreate
и onDelete
вместо того , onWrite
как вы будете называть onWrite
обновления означает , что вы тратите больше денег на ненужные функции вызовов (если вы обновляете документы в коллекции).
Прямого выбора нет. Вы не можете этого сделать db.collection("CollectionName").count()
. Ниже приведены два способа узнать количество документов в коллекции.
db.collection("CollectionName").get().subscribe(doc=>{
console.log(doc.size)
})
Используя приведенный выше код, количество прочитанных вами документов будет равно размеру документов в коллекции, и это причина, по которой следует избегать использования вышеуказанного решения.
db.collection("CollectionName").doc("counts")get().subscribe(doc=>{
console.log(doc.count)
})
Выше мы создали документ со счетчиками имен для хранения всей информации о счетчиках. Вы можете обновить документ счетчиков следующим образом: -
по цене (Document Read = 1) и быстрому извлечению данных - это хорошее решение.
Обходной путь:
напишите счетчик в документе firebase, который вы увеличиваете в транзакции каждый раз, когда создаете новую запись
Вы сохраняете счетчик в поле вашей новой записи (например: позиция: 4).
Затем вы создаете индекс для этого поля (позиция DESC).
Вы можете пропустить + ограничение с помощью запроса. Где ("позиция", "<" x) .OrderBy ("позиция", DESC)
Надеюсь это поможет!
Я много пробовал с разными подходами. И наконец, улучшаю один из методов. Для начала нужно создать отдельную коллекцию и сохранить в ней все события. Во-вторых, вам нужно создать новую лямбду, которая будет срабатывать по времени. Эта лямбда будет подсчитывать события в коллекции событий и очищать документы событий. Подробности кода в статье. https://medium.com/@ihor.malaniuk/how-to-count-documents-in-google-cloud-firestore-b0e65863aeca
Я создал универсальную функцию, используя все эти идеи для обработки всех встречных ситуаций (кроме запросов).
Единственное исключение - когда вы делаете так много записей в секунду, это замедляет вас. Примером могут служить лайки на популярном посте. Например, для публикации в блоге это излишне, и вам обойдется дороже. Я предлагаю в этом случае создать отдельную функцию с использованием шардов: https://firebase.google.com/docs/firestore/solutions/counters
// trigger collections
exports.myFunction = functions.firestore
.document('{colId}/{docId}')
.onWrite(async (change: any, context: any) => {
return runCounter(change, context);
});
// trigger sub-collections
exports.mySubFunction = functions.firestore
.document('{colId}/{docId}/{subColId}/{subDocId}')
.onWrite(async (change: any, context: any) => {
return runCounter(change, context);
});
// add change the count
const runCounter = async function (change: any, context: any) {
const col = context.params.colId;
const eventsDoc = '_events';
const countersDoc = '_counters';
// ignore helper collections
if (col.startsWith('_')) {
return null;
}
// simplify event types
const createDoc = change.after.exists && !change.before.exists;
const updateDoc = change.before.exists && change.after.exists;
if (updateDoc) {
return null;
}
// check for sub collection
const isSubCol = context.params.subDocId;
const parentDoc = `${countersDoc}/${context.params.colId}`;
const countDoc = isSubCol
? `${parentDoc}/${context.params.docId}/${context.params.subColId}`
: `${parentDoc}`;
// collection references
const countRef = db.doc(countDoc);
const countSnap = await countRef.get();
// increment size if doc exists
if (countSnap.exists) {
// createDoc or deleteDoc
const n = createDoc ? 1 : -1;
const i = admin.firestore.FieldValue.increment(n);
// create event for accurate increment
const eventRef = db.doc(`${eventsDoc}/${context.eventId}`);
return db.runTransaction(async (t: any): Promise<any> => {
const eventSnap = await t.get(eventRef);
// do nothing if event exists
if (eventSnap.exists) {
return null;
}
// add event and update size
await t.update(countRef, { count: i });
return t.set(eventRef, {
completed: admin.firestore.FieldValue.serverTimestamp()
});
}).catch((e: any) => {
console.log(e);
});
// otherwise count all docs in the collection and add size
} else {
const colRef = db.collection(change.after.ref.parent.path);
return db.runTransaction(async (t: any): Promise<any> => {
// update size
const colSnap = await t.get(colRef);
return t.set(countRef, { count: colSnap.size });
}).catch((e: any) => {
console.log(e);
});;
}
}
Это обрабатывает события, приращения и транзакции. Прелесть в этом заключается в том, что если вы не уверены в точности документа (возможно, еще в бета-версии), вы можете удалить счетчик, чтобы он автоматически складывал их при следующем триггере. Да, это стоит денег, иначе не удаляйте его.
То же самое для подсчета:
const collectionPath = 'buildings/138faicnjasjoa89/buildingContacts';
const colSnap = await db.doc('_counters/' + collectionPath).get();
const count = colSnap.get('count');
Кроме того, вы можете создать задание cron (запланированная функция) для удаления старых событий, чтобы сэкономить деньги на хранилище базы данных. Вам нужен хотя бы план пламени, и может быть еще какая-то конфигурация. Например, вы можете запускать его каждое воскресенье в 23:00. https://firebase.google.com/docs/functions/schedule-functions
Это не проверено , но должно работать с несколькими настройками:
exports.scheduledFunctionCrontab = functions.pubsub.schedule('5 11 * * *')
.timeZone('America/New_York')
.onRun(async (context) => {
// get yesterday
const yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);
const eventFilter = db.collection('_events').where('completed', '<=', yesterday);
const eventFilterSnap = await eventFilter.get();
eventFilterSnap.forEach(async (doc: any) => {
await doc.ref.delete();
});
return null;
});
И наконец, не забудьте защитить свои коллекции в firestore.rules :
match /_counters/{document} {
allow read;
allow write: if false;
}
match /_events/{document} {
allow read, write: if false;
}
Обновление: запросы
Добавляя к моему другому ответу, если вы также хотите автоматизировать подсчет запросов, вы можете использовать этот измененный код в своей облачной функции:
if (col === 'posts') {
// counter reference - user doc ref
const userRef = after ? after.userDoc : before.userDoc;
// query reference
const postsQuery = db.collection('posts').where('userDoc', "==", userRef);
// add the count - postsCount on userDoc
await addCount(change, context, postsQuery, userRef, 'postsCount');
}
return delEvents();
Что автоматически обновит postsCount в userDocument. Таким образом вы можете легко добавить еще один ко многим счетчикам. Это просто дает вам представление о том, как вы можете автоматизировать вещи. Я также дал вам другой способ удалить события. Вы должны прочитать каждую дату, чтобы удалить ее, так что это не спасет вас от удаления их позже, просто замедлит работу.
/**
* Adds a counter to a doc
* @param change - change ref
* @param context - context ref
* @param queryRef - the query ref to count
* @param countRef - the counter document ref
* @param countName - the name of the counter on the counter document
*/
const addCount = async function (change: any, context: any,
queryRef: any, countRef: any, countName: string) {
// events collection
const eventsDoc = '_events';
// simplify event type
const createDoc = change.after.exists && !change.before.exists;
// doc references
const countSnap = await countRef.get();
// increment size if field exists
if (countSnap.get(countName)) {
// createDoc or deleteDoc
const n = createDoc ? 1 : -1;
const i = admin.firestore.FieldValue.increment(n);
// create event for accurate increment
const eventRef = db.doc(`${eventsDoc}/${context.eventId}`);
return db.runTransaction(async (t: any): Promise<any> => {
const eventSnap = await t.get(eventRef);
// do nothing if event exists
if (eventSnap.exists) {
return null;
}
// add event and update size
await t.set(countRef, { [countName]: i }, { merge: true });
return t.set(eventRef, {
completed: admin.firestore.FieldValue.serverTimestamp()
});
}).catch((e: any) => {
console.log(e);
});
// otherwise count all docs in the collection and add size
} else {
return db.runTransaction(async (t: any): Promise<any> => {
// update size
const colSnap = await t.get(queryRef);
return t.set(countRef, { [countName]: colSnap.size }, { merge: true });
}).catch((e: any) => {
console.log(e);
});;
}
}
/**
* Deletes events over a day old
*/
const delEvents = async function () {
// get yesterday
const yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);
const eventFilter = db.collection('_events').where('completed', '<=', yesterday);
const eventFilterSnap = await eventFilter.get();
eventFilterSnap.forEach(async (doc: any) => {
await doc.ref.delete();
});
return null;
}
Я также должен предупредить вас, что универсальные функции будут запускаться в каждый период вызова onWrite. Может быть дешевле запускать функцию только для экземпляров onCreate и onDelete ваших конкретных коллекций. Как и в случае с базой данных noSQL, которую мы используем, повторяющийся код и данные могут сэкономить вам деньги.
offset
& limit
:public int collectionCount(String collection) {
Integer page = 0;
List<QueryDocumentSnapshot> snaps = new ArrayList<>();
findDocsByPage(collection, page, snaps);
return snaps.size();
}
public void findDocsByPage(String collection, Integer page,
List<QueryDocumentSnapshot> snaps) {
try {
Integer limit = 26000;
FieldPath[] selectedFields = new FieldPath[] { FieldPath.of("id") };
List<QueryDocumentSnapshot> snapshotPage;
snapshotPage = fireStore()
.collection(collection)
.select(selectedFields)
.offset(page * limit)
.limit(limit)
.get().get().getDocuments();
if (snapshotPage.size() > 0) {
snaps.addAll(snapshotPage);
page++;
findDocsByPage(collection, page, snaps);
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
findDocsPage
это рекурсивный метод поиска всех страниц коллекции
selectedFields
для оптимизации запроса и получения только поля идентификатора вместо всего тела документа
limit
максимальный размер каждой страницы запроса
page
определить начальную страницу для разбивки на страницы
Судя по тестам, которые я провел, он хорошо работал для коллекций, содержащих примерно до 120 тысяч записей !
Мне потребовалось время, чтобы заставить это работать на основе некоторых из приведенных выше ответов, поэтому я подумал, что поделюсь им для использования другими. Надеюсь, это будет полезно.
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
exports.countDocumentsChange = functions.firestore.document('library/{categoryId}/documents/{documentId}').onWrite((change, context) => {
const categoryId = context.params.categoryId;
const categoryRef = db.collection('library').doc(categoryId)
let FieldValue = require('firebase-admin').firestore.FieldValue;
if (!change.before.exists) {
// new document created : add one to count
categoryRef.update({numberOfDocs: FieldValue.increment(1)});
console.log("%s numberOfDocs incremented by 1", categoryId);
} else if (change.before.exists && change.after.exists) {
// updating existing document : Do nothing
} else if (!change.after.exists) {
// deleting document : subtract one from count
categoryRef.update({numberOfDocs: FieldValue.increment(-1)});
console.log("%s numberOfDocs decremented by 1", categoryId);
}
return 0;
});
Это использует подсчет для создания числового уникального идентификатора. В моем использовании я никогда не буду уменьшать значение , даже если document
идентификатор, для которого требуется идентификатор, будет удален.
При collection
создании, которому требуется уникальное числовое значение
appData
одним документом set
с .doc
идентификаторомonly
uniqueNumericIDAmount
0 вfirebase firestore console
doc.data().uniqueNumericIDAmount + 1
как уникальный числовой идентификаторappData
коллекцию uniqueNumericIDAmount
с помощьюfirebase.firestore.FieldValue.increment(1)
firebase
.firestore()
.collection("appData")
.doc("only")
.get()
.then(doc => {
var foo = doc.data();
foo.id = doc.id;
// your collection that needs a unique ID
firebase
.firestore()
.collection("uniqueNumericIDs")
.doc(user.uid)// user id in my case
.set({// I use this in login, so this document doesn't
// exist yet, otherwise use update instead of set
phone: this.state.phone,// whatever else you need
uniqueNumericID: foo.uniqueNumericIDAmount + 1
})
.then(() => {
// upon success of new ID, increment uniqueNumericIDAmount
firebase
.firestore()
.collection("appData")
.doc("only")
.update({
uniqueNumericIDAmount: firebase.firestore.FieldValue.increment(
1
)
})
.catch(err => {
console.log(err);
});
})
.catch(err => {
console.log(err);
});
});
var variable=0
variable=variable+querySnapshot.count
тогда, если вы хотите использовать его в переменной String, тогда
let stringVariable= String(variable)
firebaseFirestore.collection("...").addSnapshotListener(new EventListener<QuerySnapshot>() {
@Override
public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e) {
int Counter = documentSnapshots.size();
}
});