Как добавить субколлекцию в документ в Firebase Cloud Firestore

В документации нет примеров добавления подколлекции в документ. Я знаю, как добавить документ в коллекцию и как добавить данные в документ, но как мне добавить коллекцию (подколлекцию) в документ?

Не должно ли быть какого-то метода, подобного этому:

dbRef.document("example").addCollection("subCollection")

Ответ 1

Предполагая, что у нас есть приложение чата, структура базы данных которого выглядит примерно так:

enter image description here

Чтобы написать subCollection в документе, используйте следующий код:

DocumentReference messageRef = db
    .collection("rooms").document("roomA")
    .collection("messages").document("message1");

Если вы хотите создать коллекцию messages и вызвать addDocument() 1000 раз, это наверняка будет дорого, но именно так работает Firestore. Вы можете переключиться на базу данных Firebase Realtime, если хотите, где количество записей не имеет значения. Но что касается поддерживаемых типов данных в Firestore, на самом деле вы можете использовать массив, потому что это поддерживается. В базе данных Firebase Realtime вы также можете использовать array, но это анти-паттерн. Одна из многих причин, по которым Firebase рекомендует не использовать массивы, состоит в том, что это делает невозможным написание правил безопасности.

Cloud Firestore может хранить массивы, он не поддерживает запросы членов массива или обновление отдельных элементов массива. Однако вы все еще можете моделировать данные такого рода, используя другие возможности Cloud Firestore. Вот документация, где очень хорошо объяснено.

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

collection -> document -> subCollection -> document

Ответ 2

Вот мой код:

firebase.firestore().collection($scope.longLanguage + 'Words').doc($scope.word).set(wordData)
  .then(function() {
    console.log("Collection added to Firestore!");
    var promises = [];
    promises.push(firebase.firestore().collection($scope.longLanguage + 'Words').doc($scope.word).collection('AudioSources').doc($scope.accentDialect).set(accentDialectObject));
    promises.push(firebase.firestore().collection($scope.longLanguage + 'Words').doc($scope.word).collection('FunFacts').doc($scope.longLanguage).set(funFactObject));
    promises.push(firebase.firestore().collection($scope.longLanguage + 'Words').doc($scope.word).collection('Translations').doc($scope.translationLongLanguage).set(translationObject));
    Promise.all(promises).then(function() {
      console.log("All subcollections were added!");
    })
    .catch(function(error){
      console.log("Error adding subcollections to Firestore: " + error);
    });
  })
  .catch(function(error){
    console.log("Error adding document to Firestore: " + error);
  });

Это делает коллекцию EnglishWords, который имеет документ of. Документ of имеет три подколлекций: AudioSources (записи слова в американских и британских акцентах), FunFacts и Translations. Подсобрание Translations имеют один документ: Spanish. В Spanish документе есть три пары ключевого значения, говорящие вам, что "de" - испанский перевод "of".

Первая строка кода создает сборник EnglishWords. Мы ждем обещания разрешить с. .then, а затем создадим три подкомпонента. Promise.all сообщает нам, когда установлены все три подкомпонента.

IMHO, я использую массивы в Firestore, когда весь массив загружается и загружается вместе, то есть мне не нужно обращаться к отдельным элементам. Например, массив букв слова "of" будет ['o', 'f']. Пользователь может спросить: "Как мне написать?"? Пользователь не собирается спрашивать: "Какое второе письмо в?"?

Я использую коллекции, когда мне нужно получить доступ к отдельным элементам, например документам. С более старой базой данных Firebase Realtime мне пришлось загружать массивы, а затем перебирать массивы с помощью forEach чтобы получить элемент, который я хотел. Это было много кода, и с глубокой структурой данных и/или большими массивами я загружал тонны данных, которые мне не нужны, и замедлял мое приложение, работающее для forEach на больших массивах. Firestore помещает итераторы в базу данных на их конце, чтобы я мог запросить один элемент, и он отправляет мне только этот элемент, сохраняя пропускную способность и ускоряя выполнение моего приложения. Это может не иметь значения для веб-приложения, если ваш компьютер имеет широкополосное соединение, но для мобильных приложений с плохими соединениями данных и медленными устройствами это важно.

Вот две фотографии моего Firestore: enter image description here

enter image description here

Ответ 3

Здесь вариант, в котором подколлекция хранит значения идентификаторов на уровне коллекции, а не внутри документа, где подколлекция представляет собой поле с дополнительными данными.

Это полезно для подключения сопоставления идентификатора "1-ко-многим" без необходимости просматривать дополнительный документ:

function fireAddStudentToClassroom(studentUserId, classroomId) {

    var db = firebase.firestore();
    var studentsClassroomRef =
        db.collection('student_class').doc(classroomId)
          .collection('students');

    studentsClassroomRef
        .doc(studentUserId)
        .set({})
        .then(function () {
            console.log('Document Added ');
        })
        .catch(function (error) {
            console.error('Error adding document: ', error);
        });
}

Благодаря @Alex ответу

Этот ответ немного отличается от исходного вопроса здесь, где он явно просит добавить коллекцию в документ. Тем не менее, после поиска решения для этого сценария и не найдя упоминаний в документации или SO, этот пост кажется разумным местом для обмена выводами

Ответ 4

слишком поздно для ответа, но вот что сработало для меня,

        mFirebaseDatabaseReference?.collection("conversations")?.add(Conversation("User1"))
            ?.addOnSuccessListener { documentReference ->
                Log.d(TAG, "DocumentSnapshot written with ID: " + documentReference.id)
                mFirebaseDatabaseReference?.collection("conversations")?.document(documentReference.id)?.collection("messages")?.add(Message(edtMessage?.text.toString()))
            }?.addOnFailureListener { e ->
                Log.w(TAG, "Error adding document", e)
            }

добавьте прослушиватель успеха для добавления документа и используйте сгенерированный Firebase ID для пути. Используйте этот идентификатор для полного пути для новой коллекции, которую вы хотите добавить. IE - dbReference.collection('yourCollectionName'). Document (firebaseGeneratedID).collection('yourCollectionName'). Add (yourDocumentPOJO/Object)

Ответ 5

DocumentReference messageRef = db
.collection("rooms").document("roomA")
.collection("messages").document("message1");

Этот код выше создает виртуальный документ roomA, который возвращает false, когда вы проверяете, существует ли документ. Кто-нибудь знает, как избежать виртуальных документов?