Коллекция запросов 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)
надеюсь, это поможет