Я просто изучаю новый Firebase Firestore, и он содержит тип данных с именем ссылка. Мне непонятно, что это делает.

  • Это как внешний ключ?
  • Можно ли его использовать для указания на коллекцию, которая находится где-то еще?
  • Если ссылка является действительной ссылкой, могу ли я использовать ее для запросов? Например, могу ли я иметь ссылку, указывающую непосредственно на пользователя, вместо сохранения идентификатора пользователя в текстовом поле? Могу ли я использовать эту ссылку пользователя для запросов?

Ответы (7)

Ссылки очень похожи на внешние ключи.

В выпущенных в настоящее время SDK не могут храниться ссылки на другие проекты. В проекте ссылки могут указывать на любой другой документ в любой другой коллекции.

Вы можете использовать ссылки в запросах, как и любое другое значение: для фильтрации, упорядочивания и для разбиения на страницы (startAt / startAfter).

В отличие от внешних ключей в базе данных SQL, ссылки бесполезны для выполнения объединений в одном запросе. Вы можете использовать их для зависимых поисков (которые кажутся похожими на соединение), но будьте осторожны, потому что каждый переход приведет к еще одному круговому обращению к серверу.

Добавляем ниже то, что сработало для меня, используя ссылки в Firestore.

Как говорят другие ответы, это похоже на внешний ключ. Атрибут ссылки не возвращает данные справочного документа. Например, у меня есть список продуктов со ссылкой на userRef в качестве одного из атрибутов продукта. Получая список продуктов, я получаю ссылку на пользователя, создавшего этот продукт. Но он не дает мне подробностей о пользователе в этой ссылке. Я использовал другой бэкэнд в качестве сервисов с указателями до этого, у которых был флаг «populate: true», который возвращает данные пользователя, а не только ссылочный идентификатор пользователя, который было бы здорово иметь здесь (надеюсь, что это будет улучшение в будущем. ).

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

Установить ссылку на коллекцию:

let data = {
  name: 'productName',
  size: 'medium',
  userRef: db.doc('users/' + firebase.auth().currentUser.uid)
};
db.collection('products').add(data);

Получите коллекцию (продукты) и все ссылки на каждый документ (данные пользователя):

db.collection('products').get()
    .then(res => {
      vm.mainListItems = [];
      res.forEach(doc => {
        let newItem = doc.data();
        newItem.id = doc.id;
        if (newItem.userRef) {
          newItem.userRef.get()
          .then(res => { 
            newItem.userData = res.data() 
            vm.mainListItems.push(newItem);
          })
          .catch(err => console.error(err));
        } else {
          vm.mainListItems.push(newItem);  
        }

      });
    })
    .catch(err => { console.error(err) });

Надеюсь, это поможет

С опозданием, у этого блога есть два преимущества:

enter image description here

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

У меня не было бы 200 составных индексов, но есть некоторые ограничения.

Кроме того, с точки зрения правил безопасности довольно распространено ограничение дочерних документов на основе некоторых данных, которые существуют в их родительских документах, и это значительно проще сделать, когда у вас есть данные, настроенные в подколлекциях.

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

Согласно #AskFirebase https://youtu.be/Elg2zDVIcLo?t=276 основным вариантом использования на данный момент является ссылка в пользовательском интерфейсе консоли Firebase

Для тех, кто ищет решение Javascript для запроса по ссылке - концепция заключается в том, что вам необходимо использовать объект «ссылка на документ» в операторе запроса

teamDbRef = db.collection('teams').doc('CnbasS9cZQ2SfvGY2r3b'); /* CnbasS9cZQ2SfvGY2r3b being the collection ID */
//
//
db.collection("squad").where('team', '==', teamDbRef).get().then((querySnapshot) => {
  //
}).catch(function(error) {
  //
});

(Престижность ответу здесь: https://stackoverflow.com/a/53141199/1487867)

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

Вот пример того, как вы могли бы использовать его в firebase JavaScript SDK 9, модульная версия.

предположим, что ваш firestore имеет коллекцию под названием products и содержит следующий документ.

{
  name: 'productName',
  size: 'medium',
  userRef: 'user/dfjalskerijfs'
}

здесь у пользователей есть ссылка на документ из коллекции users. мы можем использовать следующий сегмент кода, чтобы получить продукт, а затем получить пользователя по ссылке.

import { collection, getDocs, getDoc, query, where } from "firebase/firestore";
import { db } from "./main"; // firestore db object

let productsWithUser = []
const querySnaphot = await getDocs(collection(db, 'products'));
querySnapshot.forEach(async (doc) => {
  let newItem = {id: doc.id, ...doc.data()};
  if(newItem.userRef) {
    let userData = await getDoc(newItem.userRef);
    if(userData.exists()) {
      newItem.userData = {userID: userData.id, ...userData.data()}
    }
    productwithUser.push(newItem);
  } else {
    productwithUser.push(newItem);
  }
});

здесь collection, getDocs, getDoc, query, где - модули, связанные с хранилищем данных, которые мы можем использовать для получения данных, когда это необходимо. мы используем ссылку на пользователя, возвращенную из документа products, непосредственно для получения пользовательского документа для этой ссылки, используя следующий код,

let userData = await getDoc(newItem.userRef);

, чтобы узнать больше о том, как использовать modular ver SDK, см. официальную документацию, чтобы узнать больше.

Автоматическое СОЕДИНЕНИЕ:

ДОК

expandRef  (obs: Observable , fields: any [] = []): Observable  {
  return obs.pipe (
    switchMap ((doc: any) => doc? combLatest (
      (fields.length === 0? Object.keys (doc) .filter (
        (k: любой) => {
          const p = doc [k] instanceof DocumentReference;
          если (p) fields.push (k);
          return p;
        }
      ): fields) .map ((f: any) => docData  (doc [f]))
    ).трубка(
      map ((r: any) => fields.reduce (
        (предыдущая: любая, текущая: любая) =>
          ({... пред, [curr]: r.shift ()})
        , док)
      )
    ): из (док))
  );
}

ЗАБОР

expandRefs  (
  obs: Observable ,
  поля: любые [] = []
): Observable  {
  return obs.pipe (
    switchMap ((col: any []) =>
      col.length! == 0? combLatest (col.map ((doc: any) =>
        (fields.length === 0? Object.keys (doc) .filter (
          (k: любой) => {
            const p = doc [k] instanceof DocumentReference;
            если (p) fields.push (k);
            return p;
          }
        ): fields) .map ((f: any) => docData  (doc [f]))
      ) .reduce ((acc: any, val: any) => [] .concat (acc, val)))
        .трубка(
          карта ((h: любой) =>
            col.map ((doc2: любой) =>
              fields.reduce (
                (предыдущая: любая, текущая: любая) =>
                  ({... пред, [curr]: h.shift ()})
                , doc2
              )
            )
          )
        ): из (столбец)
    )
  );
}

Просто поместите эту функцию вокруг наблюдаемого, и она автоматически расширит все ссылочные типы данных, обеспечивая автоматические соединения.

Использование

this.posts = expandRefs (
  collectionData (
    запрос(
      коллекция (this.afs, 'posts'),
      где ('опубликовано', '==', истина),
      orderBy (fieldSort)
    ), {idField: 'id'}
  )
);

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

['imageDoc', 'authorDoc']

Это увеличит скорость!

Добавьте .pipe (take (1)). ToPromise (); в конце для версии обещания!

См. здесь для получения дополнительной информации. Работает в Firebase 8 или 9!

Просто!

Дж

2022 WebDevInsider