Коллекция запросов AngularFire2 для документов, которые имеют значение в массиве эффективно

У меня есть следующая модель в Angular 6 cli/TS/AngularFire, которую я пытаюсь построить. Я новичок во всех этих вещах.

export class Book {
  constructor(
    public id: string,
    public title: string,
    public genres: any[]

  ) {}
}

И я хочу быть в состоянии найти все книги этого жанра, хранящиеся в Firebase Cloud Firestore, используя AngularFire2.

Стандартный запрос выглядит следующим образом ( документация):

afs.collection('books', ref => ref.where('size', '==', 'large'))

В идеале я хочу позвонить в Firebase, который не получает все документы в коллекции, поэтому он более эффективен (скажите мне, если это неправильно). Например, как то так.

afs.collection('books', ref => ref.where(book.genres.containsAny(array of user defined genres)));

У меня ограниченное понимание моделирования данных NoSQL, но я бы с радостью изменил модель, если есть что-то более эффективное, что останется быстрым с 1000, 30 000 или даже 100 000 документов.

Прямо сейчас я делаю это.

 filterArray = ["Genetic Engineering", "Science Fiction"];
 filteredBooks: Book[] = [];
 ngOnInit() {

    this.db.collection<Book>('books')
     .valueChanges().subscribe(books => {
       for (var i=0; i < books.length; i++) {
         if (books[i].genres.some(v => this.filterArray.includes(v))) {
           this.filteredBooks.push(books[i]);
         }
       }
    });
 }

Это работает для фильтрации документов, но есть ли более эффективный способ с точки зрения скорости и масштабируемости (получить только совпадающие документы вместо всех)?

0 ответов

Вы правы ограничить документы в первую очередь. Вы не хотите тянуть 30 тыс. Документов, затем фильтруйте их. И вы на правильном пути, но ваше форматирование было не совсем правильным. Вы хотите сделать что-то вроде этого:

afs.collection<book>('books', ref => ref.where('genres', 'array-contains', genre)

Я считаю, что на данный момент вы не можете передать в массив, как:

afs.collection<book>('books', ref => ref.where('genres', 'array-contains', genres) // note that genres is plural implying a list of genres

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

Теперь вы упомянули, что вам также хотелось бы предложить хранить данные по-другому. Я бы порекомендовал вам НЕ использовать массив для жанров. Вместо этого сделайте карту (в основном, объект), например так:

author: string;
title: string;
...
genres: map

Тогда вы можете сделать это:

author: 'Herman Melville'
title: 'Moby Dick'
...
genres: {
    'classics': true
    'nautical': true
}

И тогда вы можете отфильтровать коллекцию следующим образом:

afs.collection<book>('books', ref => ref.where('genres.classics', '==', true).where('genres.nautical', '==' true)

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

Другие вопросы по тегам