简体   繁体   English

如何使用 snapshotChanges() 方法获取键值和过滤数据?

[英]How to use snapshotChanges() method to get both key value and filter the data?

I'm working on an Angular Firebase Project, where I need to filter my database as well get the key values.我正在做一个 Angular Firebase 项目,我需要在其中过滤我的数据库并获取键值。 Currently I'm using valueChanges() method in my service code ( inside getUnreadBooks and getFavoriteBooks methods, as shown below ) to get the data and filter it.目前我在我的服务代码中使用valueChanges()方法(在 getUnreadBooks 和 getFavoriteBooks 方法中,如下所示)来获取数据并对其进行过滤。 But it gives me key value as 'undefined', when I try to get key value inside my template file.但是当我尝试在我的模板文件中获取键值时,它给我的键值为“未定义”。 I tried to go with snapshotChanges() method, but can't work around how to use it to get key values along with filtering the data.我尝试使用snapshotChanges()方法,但无法解决如何使用它来获取键值以及过滤数据的问题。 Below are my Angular FirebaseService, home.component.ts ( in which I am injecting my service code ) and home.component.html (template file) Code respectively:下面分别是我的 Angular FirebaseService、home.component.ts(我在其中注入我的服务代码)和 home.component.html(模板文件)代码:

import { Injectable } from '@angular/core';
import { AngularFireDatabase } from 'angularfire2/database';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';

@Injectable()
export class FirebaseService {

  books: Observable<any[]>;
  unreadBooks;
  favoriteBooks;

  constructor(private db: AngularFireDatabase) {}

  getBooks(){
        this.books = this.db.list('/books').valueChanges() as Observable<any[]>;
        return this.books;
    }       

  getFavoriteBooks(){
    this.favoriteBooks = this.db.list('/books').valueChanges() as Observable<any[]>;
    this.favoriteBooks = this.favoriteBooks.map(books => {
        const topRatedBooks = books.filter(item =>  item.rate>4);
        return topRatedBooks;
    })
    return this.favoriteBooks;
  }

  getUnreadBooks(){
    this.unreadBooks = this.db.list('/books').valueChanges() as Observable<any[]>;
    this.unreadBooks = this.unreadBooks.map(books => {
        const ub = books.filter(item => item.dateread == null);
        return ub;
    })
    return this.unreadBooks;
  }
}

Home.Component.ts file => Home.Component.ts 文件 =>

import { Component, OnInit } from '@angular/core';
import { FirebaseService } from '../../services/firebase.service';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {

  //favorite Books
  favoriteBooks: any;
  unreadBooks: any;

  constructor(private firebaseService: FirebaseService) { }

  ngOnInit() {
    this.firebaseService.getFavoriteBooks()
        .subscribe(favBooks => {
            this.favoriteBooks = favBooks;
            console.log(this.favoriteBooks);
        })
    this.firebaseService.getUnreadBooks()
        .subscribe(ubBooks => {
            this.unreadBooks = ubBooks;
            console.log('Unread Books:', this.unreadBooks);
        })
  }

}

Home.component.html file => Home.component.html 文件 =>

<mat-toolbar>
    My Top Rated Books
</mat-toolbar>
<mat-grid-list cols="3">
    <mat-grid-tile *ngFor="let book of favoriteBooks">
        <mat-card>
            <mat-card-header>
                <mat-card-title>
                    <h4>{{book.title}}</h4>
                </mat-card-title>
            </mat-card-header>
            <img mat-card-image src="{{book.imageUrl}}" alt="{{book.title}}">
            <mat-card-actions>
                <button mat-button mat-raised-button class="detailsButton" [routerLink]="['/book/'+book.$key]">
                    <i class="material-icons">visibility</i>Book Details</button>
                <button mat-button mat-raised-button class="editButton" [routerLink]="['/editbook/'+book.$key]">
                    <i class="material-icons">mode_edit</i>Edit Book</button>
            </mat-card-actions>
        </mat-card>     
    </mat-grid-tile>
</mat-grid-list>

<mat-toolbar>
    Books I have not read yet
</mat-toolbar>
<mat-grid-list cols="3">
    <mat-grid-tile *ngFor="let book of unreadBooks">
        <mat-card>
            <mat-card-header>
                <mat-card-title>
                    <h4>{{book.title}}</h4>
                </mat-card-title>
            </mat-card-header>
            <img mat-card-image src="{{book.imageUrl}}" alt="{{book.title}}">
            <mat-card-actions>
                <button mat-button mat-raised-button class="detailsButton" [routerLink]="['/book/'+book.$key]">
                    <i class="material-icons">visibility</i>Book Details</button>
                <button mat-button mat-raised-button class="editButton" [routerLink]="['/editbook/'+book.$key]">
                    <i class="material-icons">mode_edit</i>Edit Book</button>
            </mat-card-actions>
        </mat-card>     
    </mat-grid-tile>
</mat-grid-list>

Declare a function to add id to your Object:声明一个函数以将 id 添加到您的对象:

documentToDomainObject = _ => {
    const object = _.payload.doc.data();
    object.id = _.payload.doc.id;
    return object;
}

And use it in your getBooks method:并在您的 getBooks 方法中使用它:

getBooks(){
  this.books = this.db.list('/books').snapshotChanges()
  .pipe(map(actions => actions.map(this.documentToDomainObject)));

  return this.books;
}

In my case I solved it by importing rxjs operator map, combined by.pipe在我的例子中,我通过导入 rxjs 运算符映射来解决它,结合 by.pipe

import { map } from 'rxjs/operators';

Example:例子:

import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { AngularFirestore } from 'angularfire2/firestore';
import { IdeaService } from './app.service';

import { config } from './app.config';
import { Idea } from './app.model';
import {
  AngularFirestoreDocument,
  AngularFirestoreCollection
} from 'angularfire2/firestore';

@Component({
selector: 'app-root',
template: `
    <ul>
        <li *ngFor="let idea of ideas | async">
            <pre>{{ idea | json }}</pre>
        </li>
    </ul>
`
})
export class AppComponent {
  public ideasCollection: AngularFirestoreCollection<Idea>;
  public ideas: Observable<any[]>;

  constructor(db: AngularFirestore, private ideaService: IdeaService) {
    this.ideasCollection = db.collection<Idea>(config.collection_endpoint);
    this.ideas = this.ideasCollection.snapshotChanges().pipe(
        map(actions => {
          return actions.map(a => {
            const data = a.payload.doc.data() as Idea;
            const id = a.payload.doc.id;
            return { id, ...data };
          });
        }));
    }
}

You need to import the rxjs operator map import { map } from 'rxjs/operators';您需要导入 rxjs 运算符 map import { map } from 'rxjs/operators'; // in rxjs 6 version // 在 rxjs 6 版本中

I imported this import { map } from 'rxjs/operators' and this solved my problemimport { map } from 'rxjs/operators' ,这解决了我的问题

This is with angular 9 and it's working fine.this is set up in the service.ts and get the data from particular.ts file and just normally reader the data into template这是 angular 9 并且工作正常。这是在 service.ts 中设置的,并从 particular.ts 文件中获取数据,通常只是将数据读入模板

 getAll() {
    return this.database.list('/products').snapshotChanges()
    .pipe(map( action => action
      .map(a => {
        const key = a.payload.key;
        const data = a.payload.val();
        return  data;
      })));
  }

particular.ts特别的.ts

constructor(private productService: ProductService) {
    this.products$ = this.productService.getAll();
   }

particular.html特别的.html

<tr *ngFor="let product of products$ | async" >
    <td> {{ product.title }}</td>
    <td> {{ product.price }}</td>

 this.data.list('/expenseCategories').snapshotChanges().forEach(snapshot=> { snapshot.forEach(keys => { TransactionService.expenseCategories.push(keys.payload.key); }) });

Simple and effective solution: You will get both id and data简单有效的解决方案:您将同时获得 id 和 data

Add it in your service file in header part将它添加到标题部分的服务文件中

import { map } from 'rxjs/operators';

your getBooks method:你的 getBooks 方法:

getBooks(){
   return this.books = this.db.list('/books').snapshotChanges()
     .pipe(map(action => action
                .map(a => {
                    let obj:any = a.payload.doc.data()
                    return {
                        ...obj,
                        id: a.payload.doc.id
                    };
                })
            ));
}

From the Firebase docs, I see that you cannot get the key when using valueChanges() , you can only get it when using snapshotChanges() .从 Firebase 文档中,我看到使用valueChanges()时无法获取密钥,只能在使用snapshotChanges()时获取。

Building on Neelaka's answer, if you're using Angular 12 and the latest version of firebase, if you have a form that uses the (keyup) event binding you can get the key and also filter like so:基于 Neelaka 的回答,如果您使用的是 Angular 12 和最新版本的 firebase,如果您有一个使用(keyup)事件绑定的表单,您可以获得密钥并像这样进行过滤:

In your product.services.ts file:在您的product.services.ts文件中:

  getAll(){
    return this.db.list('/products').snapshotChanges().pipe(map(actions => {
      return actions.map(a => {
        const key = a.payload.key;
        const data = a.payload.val();
        return {data, key};
      })
    }));
  }

In admin-products.component.ts file:admin-products.component.ts文件中:

export class AdminProductsComponent implements OnDestroy {

  products!: { title: string; }[] | any;
  filteredProducts!: any[];
  subscription: Subscription;


  constructor(private productService: ProductService) {
    
    this.subscription = this.productService.getAll().subscribe(products => {
      this.filteredProducts = this.products = products; 
    });
    
   }

  filter(query: string){
    
    this.filteredProducts = (query) ? 
    this.products.filter((p: { data: {title:string}, key: string }) => p.data.title.toLocaleLowerCase().includes(query.toLocaleLowerCase())) : 
    this.products;
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }

}

In admin-products.htmladmin-products.html


<br>
<p>
    <a routerLink="/admin/products/new" class="btn btn-primary">New Product</a>
</p>
<br>
<p>
  <input #query (keyup)="filter(query.value)" type="text" class="form-control" placeholder="Search...">
</p>
<br>
<table class="table">
    <thead>
      <tr>
        <th scope="col">Title</th>
        <th scope="col">Price</th>
        <th scope="col"></th>
        <th scope="col"></th>
      </tr>
    </thead>
    <tbody>
      <tr *ngFor="let p of filteredProducts">
        <td>{{ p.data.title }}</td>
        <td>{{ p.data.price }}</td>
        <td>
            <a [routerLink]="['/admin/products/', p.key]">Edit</a> ✍️ 
        </td>
        <td>
            <a (click)="delete(p.key)" id="delete">Delete</a> 🗑 
        </td>
      </tr>
    </tbody>
  </table>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何从 kotlin 上的 firebase 数据库中获取键和值 - How go get both both key and value from firebase database on kotlin 如何删除 firestore 上的键值对? (不只是价值或关键两者) - how to delete key-value pair on firestore? (not just value or key both of them) AngularFire firestore get / snapshotchanges / valuechanges 对 observable 的操作不是异步的? - AngularFire firestore get / snapshotchanges / valuechanges action on observable is not async? 如何在可观察的 Firebase 变量中分配 SnapshotChanges? - How Can I assign the SnapshotChanges in a Observable Firebase Variable? 当键不是 Node.js 和 typescript 的分区或排序键时,如何从 dynamo db 过滤数据? - How to filter the data from dynamo db when the key is not a partition or Sort key with Node.js and typescript? 是否可以根据键的一部分过滤键值对? - Is it possible to filter key value pairs based on a section of the key? Ballerina - 如何使用参数/变量值作为地图中的键? - Ballerina - How to use parameter/variable value as key in a map? 如何从Flutter下面的JSON数据中取出key“folderName”的值? - How to retrieve the value of key "folderName" from the following JSON data in Flutter? 如何使用 Reactjs 按参考值过滤 Firestore 特定集合的文档数据 - How to filter Firestore specific collection's doc data by its reference value with Reactjs 如何在 BigQuery 中过滤地理数据 - How to filter on geography data in BigQuery
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM