Как ограничить результаты запроса collectionGroup предком? - PullRequest
0 голосов
/ 21 июня 2020

Я читал сообщение в блоге https://firebase.googleblog.com/2019/06/understanding-collection-group-queries.html, чтобы лучше понять запросы collectionGroup.

Хотя, у меня все еще есть один вопрос: как я могу ограничить результаты конкретными c предок. Позвольте мне объяснить себя.

Представьте, что у меня есть companies этого производителя cars с tyres. У нас есть разные марки tyres, используемые в разных cars. В конце концов, у нас есть отношения «многие ко многим». Я знаю, что не должен использовать этот термин в мире № SQL, но я называю собаку собакой: -)

В любом случае, мой вопрос следующий: если у нас нехватка company A определенной марки c tyre (скажем, Michelin), вам нужно будет отметить этот tyre как отсутствующий. Я бы подумал запустить запрос collectionGroup, например:

db.collectionQuery("tyre")
  .where("brand", "==", "Michelin")
  .get()
  .then(function (querySnapshot) {
    // update flag accordingly
  })

Но это обновит запас других companies.

Мой вопрос: как бы вы сузили результаты запроса collectionGroup поэтому вы обновляете только информацию tyres от компании A?

Я мог бы включить компанию A docRef в коллекцию tyres и использовать where(), чтобы сузить результаты. Это кажется правильным подходом. Тем не менее, это будет смесь между коллекцией верхнего уровня и вложенной коллекцией. Это лучшая практика?

ОБНОВЛЕНИЕ

На самом деле, я следую примеру ресторанов, чтобы поставить свои руки на firebase / firestore. В ресторане может быть несколько меню. В меню может быть несколько пунктов. Элементы можно использовать повторно и, следовательно, присутствовать в нескольких меню.

collection('restaurants').doc(..).collection('menus').doc(..).collection('items')

Мне нравится думать, что это лучший способ структурировать данные (по сравнению с коллекцией элементов верхнего уровня) . Но такие продукты, как кофе, можно легко найти в нескольких меню нескольких ресторанов. Если в одном ресторане не хватает кофе, как я могу обновить кофейные позиции для этого c ресторана, используя что-то вроде:

db.collectionQuery("items")
  .where("name", "==", "Coffee")
  .get()
  .then(function (querySnapshot) {
    // set available = false
  })

Ответы [ 2 ]

2 голосов
/ 21 июня 2020

Если в одном ресторане не хватает кофе, как я могу обновить кофейные элементы для этого c ресторана?

Используя запрос collectionGroup, вы могли бы сделать следующее:

  db.collectionQuery('items')
    .where('name', '==', 'Coffee')
    .get()
    .then(function (querySnapshot) {
      querySnapshot.forEach(function (doc) {
        const itemQuantity = doc.data().itemQuantity;
        if (itemQuantity === 0) {
          const restaurantRef = doc.ref.parent.parent.parent.parent;
          return restaurantRef.update( {....})
        }
      });
    });

, альтернативно используя свойства parent DocumentReference и CollectionReference.

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

Более эффективным способом было бы сохранить набор из счетчиков и наблюдайте за ними с помощью слушателей Firestore или облачных функций.

Наконец, обратите внимание на важный момент: вы пишете «Меню может иметь несколько элементов. Элементы могут быть повторно использованы и, следовательно, присутствовать в нескольких меню». Обратите внимание, что items документы в

collection('restaurants').doc('r1').collection('menus').doc('m1').collection('items')

и в

collection('restaurants').doc('r1').collection('menus').doc('m2').collection('items')

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

Заключение: у вас, скорее всего, должна быть одна коллекция itemsStock на restaurant, и каждый раз, когда один из элементов «потребляется / заказывается», вы уменьшаете его количество, используя FieldValue.increment(-1).

Другими словами, я советую отделить коллекции элементов, составляющих меню, от коллекции, содержащей счетчики элементов (т.е. коллекции itemsStock). Первые предназначены для выбора пунктов меню, а вторые - для управления запасами ресторана. Когда гость / покупатель выбирает / заказывает товар, вы только уменьшаете коллекцию, содержащую счетчики товаров.

Обновление после вашего комментария:

Если вы хотите обновить все элементы «лазаньи» во всех меню ресторана (например, чтобы добавить ингредиент, как вы упомянули в своем комментарии), очень общий подход действительно состоит в том, чтобы изменить все соответствующие документы (это называется дублированием данных в мире № SQL).

Вы должны использовать точный код в верхней части моего ответа: вы запрашиваете все "лазанья" »документы о товарах во всех меню ресторана и их обновление. Вы можете запустить этот процесс с помощью облачной функции, которая будет «наблюдать» за основной коллекцией, в которой у вас есть ссылочные элементы: каждый раз, когда вы изменяете do c этой коллекции (то есть элемента), вы обновляете все похожие / соответствующие элементы. c в подколлекциях меню.

0 голосов
/ 21 июня 2020

Я мог бы включить компанию A docRef в коллекцию шин и использовать where (), чтобы сузить результаты. Это кажется правильным подходом. Хотя это была бы смесь между коллекцией верхнего уровня и вложенной коллекцией. Это лучшая практика?

Это общий подход, поскольку единственный способ фильтровать документы в запросе группы сбора - использовать поля документов. Вы не можете использовать что-либо в пути к документу в качестве фильтра. В базах данных типа No SQL часто дублируются данные для облегчения запросов.

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

...