Merge new object in firebase database inside document - arrays

I have stored my data into firebase database by getting data from google sheet. The problem I am getting is every time I run the application It sets with new document Id. I want only one document in the firebase database collection.
My question is How do I merge data when I get new data object as response?
Example:
I have got following response :
0: {Id: 202, Name: 'word', Major: 'comp'}
1: {Id: 203, Name: 'John', Major: 'science'}
2: {Id: 204, Name: 'nsia', Major: 'cmpi'}
and It is stored in database.
Now when I run application again then It creates new document instead of merging new data to old document.
Example:
new data is
0: {Id: 205, Name: 'hello', Major: 'sci'}
and I want to merge object and get as
0: {Id: 202, Name: 'word', Major: 'comp'}
1: {Id: 203, Name: 'John', Major: 'science'}
2: {Id: 204, Name: 'nsia', Major: 'cmpi'}
3: {Id: 205, Name: 'hello', Major: 'sci'}
How do we do merge?
Here is my code to get data and post data
import { HttpClient } from '#angular/common/http';
import { Component, OnInit } from '#angular/core';
import { AngularFirestore, AngularFirestoreCollection } from '#angular/fire/compat/firestore';
import { Router } from '#angular/router';
import { AuthService } from '../shared/auth.service';
import { Field } from '../model/field';
#Component({
selector: 'app-landing-page',
templateUrl: './landing-page.page.html',
styleUrls: ['./landing-page.page.scss'],
})
export class LandingPagePage implements OnInit {
Object = Object;
myArray: Field[] = [];
private collection: AngularFirestoreCollection<Field>;
myCollection: any;
constructor(private auth: AuthService, private router:Router, private http :HttpClient,private afs: AngularFirestore) {
this.collection = this.afs.collection<Field>("Exceldata");
this.myCollection = this.collection.snapshotChanges();
}
ngOnInit() {
this.excelData();
this.auth.getDataFromFirebase().subscribe(myArray => {
this.myArray = myArray;
});
}
logout()
{
this.auth.signOut();
}
excelData(){
var sf = "https://docs.google.com/spreadsheets/d/1qeCEUlVt_hnuyhnoT1wxMMSv7kZW1s4cUIRLynJ0TxQ/gviz/tq?tqx=out:json";
this.http.get(sf,{responseType: 'text'}).subscribe(res=>{
const data =res.toString().match(/google\.visualization\.Query\.setResponse\(([\s\S\w]+)\)/);
if(data && data.length==2){
const obj=JSON.parse(data[1]);
const table=obj.table;
const header = table.cols.map(({label}) => label);
const rows = table.rows.map(({c}) => c.map(({v}) => v));
const values = rows.map(e => header.reduce((o, f, j) => Object.assign(o, {[f]: e[j]}), {}));
console.log(values);
if(!this.collection.doc){
this.collection.doc().set(Object.assign({}, values));
}else{
this.collection.doc().set((values),{merge: true});
}
}
});
}

I'm not sure if there's a better way of doing it but I've survived by storing my items locally eg as an array, appending new item and then saving as a new item.

Related

Attach correct data format to draw a chart

I'm new to Vuejs, vue-Chartkick, and Chartjs. I was trying to insert the restructured data into an object to draw a multiple-series chart. But it did not work.
<template>
<line-chart :data="data"></line-chart>
</template>
<script>
import axios from "axios";
export default {
name: 'SummaryGraph',
data () {
return {
data: [
{name: 'A', data: {}},
{name: 'B', data: {}}
]
}
},
created() {
let apiURL_1 = axios.get('http://localhost:3000/MyfirstData');
let apiURL_2 = axios.get('http://localhost:3000/MysecondData');
axios.all([apiURL_1, apiURL_2]).then(axios.spread((first_response, second_response) => {
this.data[0]['data'] = first_response.data.reduce(function(result, current) {return Object.assign(result, current);}, {});
this.data[1]['data'] = second_response.data.reduce(function(result, current) {return Object.assign(result, current);}, {});
})).catch(error => {
console.log(error)
});
}
}
</script>
The 1st original returned data:
[{"A":6},{"B":6},{"C":4}]
The 2nd original returned data:
[{"A":1},{"B":2},{"C":2}]
The 1st data after restructured by using reduce method.
{"A": 6,"B": 6,"C": 4}
The 2nd data after restructured by using reduce method.
{"A": 1,"B": 2,"C": 2}
If I directly insert the 1st and 2nd restructured data into the Vue instance
Like this:
<script>
export default {
name: 'SummaryGraph',
data () {
return {
data: [
{name: 'A', data: {"A": 6,"B": 6,"C": 4}},
{name: 'B', data: {"A": 1,"B": 2,"C": 2}}
]
}
}
}
</script>
It worked. The graph showed up. I don't know why.

How to store values from a service to an array in Angular?

I have a service with getter and setter methods, they return me id: number and title: String from my dialog component.
I need to store the values from the response to my data array, but I just cant figure out how.
For example:
0: {id: 0, title: "UK ",…}
1: {id: 1, title: "Usd ",…}
2: {id: 2, title: "ff ",…}
3: {id: 3, title: "yy ",…}
4: {id: 4, title: "nn ",…}
5: {id: 5, title: "mh ",…}
6: {id: 6, title: "tr ",…}
7: {id: 7, title: "es ",…}
I would be so grateful if you guys can help me out.
Here is what I got so far:
app.component.ts
export class AppComponent {
clickEventsubscription: Subscription
ngOnInit() {
}
id: number;
title: String;
data: any = [];
constructor(private share: ShareDataService) {
this.clickEventsubscription = this.share.getClickEvent().subscribe(() => {
this.initialize();
})
}
initialize() {
this.id = this.share.getId();
this.title = this.share.getTitle();
console.log(this.id, this.title);
}
}
app.component.html
<app-dialog></app-dialog>
<h2>Add values of my service into array:</h2>
<button (click)="initialize()"></button>
share-data.service.ts
import { Injectable } from '#angular/core';
import { Observable, Subject } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class ShareDataService {
title: String;
id: number;
getId() {
return this.id
}
getTitle() {
return this.title;
}
private subject = new Subject<any>();
sendClickEvent() {
this.subject.next();
}
getClickEvent(): Observable<any> {
return this.subject.asObservable();
}
}
Many thanks!
As far as I understand your question, there are several solutions to solve this
but the simplest way is to create an new object every time you trigger the initialize method which goes as follows
change this
initialize() {
this.id = this.share.getId();
this.title = this.share.getTitle();
console.log(this.id, this.title);
}
to the following
initialize(): void {
this.id = this.share.getId();
this.title = this.share.getTitle();
const newData = {
id: this.id,
title: this.title
};
this.data.push(newData);
}
There are some syntax errors and ordering issue in your code both the service and app component which should be solved (depends on what version of angular you are using).
Also you have to declare instant fields before instance declaration of instance method, this should come at the beginning of the class/interface
move this to the top of your class in share-data.service.ts
private subject = new Subject<any>();

How to set angular material data table with pagination (data source) to the data array retrieved from the database using web-API

I am working on a web based application. I use Angular and Web API to develop the application, DBMS: SQL Server Management Studio 17.
I want to populate data which are stored inside my database in a Angular Material data table.
This is my customer-req-table-datasource.ts.
import { DataSource } from '#angular/cdk/collections';
import { MatPaginator } from '#angular/material/paginator';
import { MatSort } from '#angular/material/sort';
import { map } from 'rxjs/operators';
import { Observable, of as observableOf, merge } from 'rxjs';
// TODO: Replace this with your own data model type
export interface CustomerReqTableItem {
name: string;
id: number;
}
// TODO: replace this with real data from your application
const EXAMPLE_DATA: CustomerReqTableItem[] = [
{id: 1, name: 'Hydrogen'},
{id: 2, name: 'Helium'},
{id: 3, name: 'Lithium'},
{id: 4, name: 'Beryllium'},
{id: 5, name: 'Boron'},
{id: 6, name: 'Carbon'},
{id: 7, name: 'Nitrogen'},
{id: 8, name: 'Oxygen'},
{id: 9, name: 'Fluorine'},
{id: 10, name: 'Neon'},
{id: 11, name: 'Sodium'},
{id: 12, name: 'Magnesium'},
{id: 13, name: 'Aluminum'},
{id: 14, name: 'Silicon'},
{id: 15, name: 'Phosphorus'},
{id: 16, name: 'Sulfur'},
{id: 17, name: 'Chlorine'},
{id: 18, name: 'Argon'},
{id: 19, name: 'Potassium'},
{id: 20, name: 'Calcium'},
];
This is my customer.service.ts file
import { HttpClient } from '#angular/common/http';
import { Employee } from './employee.model';
import { Customer } from './customer.model';
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class CustomerService {
formData: Customer;
list: Customer[];
readonly rootURL = 'https://localhost:44300/api';
constructor(private http: HttpClient) { }
postCustomer(formData: Customer) {
return this.http.post(this.rootURL + '/Customer', formData);
}
refreshList() {
this.http.get(this.rootURL + '/Customer').toPromise().then(res => this.list = res as Customer[]);
}
putCustomer(formData: Customer) {
return this.http.put(this.rootURL + '/Customer/' + formData.CustomerID, formData);
}
deleteCustomer(id: number) {
return this.http.delete(this.rootURL + '/Customer/' + id);
}
}
Problem: How can I set the list [] array (in the service.ts file) data and populate the angular data table?
However, my final goal is to get the data inside the database and display those data using a angular data table.
This is the simplest way that can solve your problem. Now let us create a material table with the use of mat-table, matColumnDef, matHeaderCellDef, matCellDef and matRowDef.
<mat-table #table [dataSource]="dataSource">
<ng-container matColumnDef="id">
<mat-header-cell *matHeaderCellDef> ID </mat-header-cell>
<mat-cell *matCellDef="let element"> </mat-cell>
</ng-container>
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
<mat-cell *matCellDef="let element"> </mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
We have the skeleton of the data table defined, now we have to provide data to it and the data is provided with the help of datasource and the name of the datasource we have already provided in [datasource] in mat-table. Now we will push data to the datasource in app.component.ts Following is the implementation.
import { Component } from '#angular/core';
import {MatTableDataSource} from '#angular/material';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
displayedColumns = ['id', 'name'];
dataSource = new MatTableDataSource(EXAMPLE_DATA);
}
export interface CustomerReqTableItem {
name: string;
id: number;
}
const EXAMPLE_DATA: CustomerReqTableItem[] = [
{id: 1, name: 'Hydrogen'},
{id: 2, name: 'Helium'},
{id: 3, name: 'Lithium'}
];
To enable pagination, angular provides mat-paginator directive that accepts the required parameter to perform pagination. This directive should be placed after the mat-table directive. But before using this directive, we need to import MatPaginatorModule in our material.module.ts.The following is an example.
<mat-paginator [length]="5" [pageSize]="3" [pageSizeOptions]="[5, 10, 25]">
</mat-paginator>
Here, the length is the total no. of rows, pageSize is the no. of rows displayed in a single table view(default is 50) and pageSizeOptions enables the switching between the no. of rows displayed in a single table view.
Also, we need to configure the paginator in our .ts file to automatically listen for page changes made by the user after the page view is initiated.
export class AppComponent implements AfterViewInit{
.
.
#ViewChild(MatPaginator) paginator: MatPaginator;
ngAfterViewInit() {
this.dataSource.paginator = this.paginator;
}
}

Create Array from objects in angular js

I am new in this framework. I want to convert objects into array in angular 8. But I don't get how this work.
Actually, I want to display multiple sales transactions of the a customer with status false.
So, somehow I get the values of those transaction made by the same customer as a separate different objects.
Now, I want to convert those objects into a single array so that I can iterate them in html file through *ngFor.
export class InvoicesComponent implements OnInit {
displayedColumns: string[] = ['ProductName', 'CustomerName', 'Quantity',
'Rate', 'Total'];
id;
dataSource;
salesTransaction: SalesTransactionElement[];
constructor(private service: SalesTransactionsService,
private route: ActivatedRoute)
{ }
ngOnInit() {
this.id = this.route.snapshot.paramMap.get('id');
this.service.getSalesTransaction(this.id).subscribe((singleData: any) =>
{
this.service.getAllSalesTransactions().subscribe((data: any) =>
{
data.forEach(element =>
{
if (singleData.CustomerName === element.CustomerName &&
element.Status === false) {
this.salesTransaction = element;
console.log(this.salesTransaction);
}
});
});
}
Actual Results:
/*****Separately as two objects****/
{SalesTranId: 54, ProductId: 10, CustomerId: 21, InvoiceId: null, ProductName: "Asus"}
{SalesTranId: 51, ProductId: 17, CustomerId: 21, InvoiceId: 1, ProductName: "Dell"}
Expected Results:
/**********Array of Objects************/
[{SalesTranId: 54, ProductId: 10, CustomerId: 21, InvoiceId: null, ProductName: "Asus"},
{SalesTranId: 51, ProductId: 17, CustomerId: 21, InvoiceId: 1, ProductName: "Dell"}]
Initialize the array above the constructor: salesTransaction: SalesTransactionElement[] = []
Then push into that array in your forEach handler: this.salesTransaction.push(element);
Actually you are assigned an object in your array definition of SalesTransactionElement[] so you need to push a SalesTransactionElement.
export class InvoicesComponent implements OnInit {
displayedColumns: string[] = ['ProductName', 'CustomerName', 'Quantity',
'Rate', 'Total'];
id;
dataSource;
salesTransaction: SalesTransactionElement[];
constructor(private service: SalesTransactionsService,
private route: ActivatedRoute)
{ }
ngOnInit() {
this.id = this.route.snapshot.paramMap.get('id');
this.service.getSalesTransaction(this.id).subscribe((singleData: any) =>
{
this.service.getAllSalesTransactions().subscribe((data: any) =>
{
data.forEach(element =>
{
if (singleData.CustomerName === element.CustomerName &&
element.Status === false) {
this.salesTransaction.push(element);
}
});
});
}

Normalizing my JSON response using normalizr with redux

I'm trying to reshape my Redux store so I can query by and filter my data easily.
I have an API endpoint that returns back an order.
The order looks like this at a high level:
Order
+ references
+ item_details
- category_id
- product_id
- product
So an order has many references, and the references have many item_details.
The item details has a category and product.
const data = {
id: 3939393,
discount: 0,
references: [
{
id: 123,
order_id: 3939393,
name: "order 1",
item_details: [
{
id: 100,
order_id: 3939393,
product_id: 443,
sort_order: 1,
category_id: 400,
product: {
id: 443,
name: "hello world",
price: 199
}
},
{
id: 200,
order_id: 3939393,
product_id: 8080,
sort_order: 2,
category_id: 500,
product: {
id: 8080,
name: "hello json",
price: 299
}
}
]
}
]
};
export default data;
So far my schema definitions look like this:
export const productSchema = new schema.Entity("products");
export const itemDetailSchema = new schema.Entity("itemDetails", {
product: productSchema
});
export const references = new schema.Entity("references", {
item_details: new schema.Array(itemDetailSchema)
});
export const orderSchema = new schema.Entity("orders");
const result = normalize(data, orderSchema);
console.log("result is: " + JSON.stringify(result));
How can I get the products in its own section in the normalized JSON? Currently the products are still embedded inside the JSON.
Would I use normalizr to create state "index" type looks like this:
productsInReferences: {
123: [400, 8080]
}
If not, how exactly to I generate these types of JSON lookups?
I created a codesandbox with my code so far.
https://codesandbox.io/s/xpl4n9w31q
I usually think Normalization schemes from the deepest nested structure all the way to the one containing the data for those cases. Remember that you can do explicit array definition through [someSchema], also every level should be contained on a nested schema, in this case you forgot the references: [referenceSchema] on the orderSchema.
The correct normalization would be:
// Product Schema
const productSchema = new schema.Entity("products");
// Item detail schema containing a product schema OBJECT within the property product
const itemDetailSchema = new schema.Entity("itemDetails", {
product: productSchema
});
// Reference schema containing an ARRAY of itemDetailSchemes within the property item_details
const referenceSchema = new schema.Entity("references", {
item_details: [itemDetailSchema]
});
// Order schema containing an ARRAY of reference schemes within the property references
const orderSchema = new schema.Entity("orders", {
references: [referenceSchema]
});
const result = normalize(data, orderSchema);
console.dir(result);
This would be the result after normalizing.
Object
entities:
itemDetails: {100: {…}, 200: {…}}
orders: {3939393: {…}}
products: {443: {…}, 8080: {…}}
references: {123: {…}}
result: 3939393

Resources