why id is undefined? - reactjs

I want to get the id of the doc but I got undefine when i console.log
is there a way to also include the doc id ?
this.unsubscribe = FirestoreService.getMessagesSnapshot(selected.id, selected.userId).onSnapshot((querySnapshot) => {
if(querySnapshot.size > 0) {
let tempObject = [];
querySnapshot.forEach((doc) => {
tempObject.push({
**id:doc.id,**
chatId: doc.data().chatId,
membersId: doc.data().membersId,
name: selected.name,
picRatio: doc.data().picRatio,
picUrl: doc.data().picUrl,
fileUrl: doc.data().fileUrl,
senderId: doc.data().senderId,
text: doc.data().text,
thumbUrl: doc.data().thumbUrl,
time: doc.data().time.toDate(),
videoUrl: doc.data().videoUrl,
});
});

Related

How to implement the fetching of data for different categories of products to be shown in a home page using firebase on a Reactjs project

I want to get the products across different categories to be shown on the home page. The below code only fetches data from a single category. How do I go about fetching products from multiple categories. Should I use promises ? I feel like there will be a lot of redundant code. Is there a better way?
fetchProducts = async ( category )=>{
let productsRef = projectFirestore.collection("products");
let query = productsRef;
query = productsRef.where('category', '==', 'Beverage');
query.get().then((querySnapshot) => {
let products = [];
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
products.push({
name : doc.data().name,
price : doc.data().price,
prev_price : doc.data().prev_price,
discount : doc.data().product_discount,
id : doc.id,
src : doc.data().pictures[0].src,
rating: doc.data().rating
});
});
this.setState(() => {
return { products };
}, this.checkCartItems);
})
Edit: Here's the correct solution: docs - https://firebase.google.com/docs/firestore/query-data/queries#in_not-in_and_array-contains-any
fetchProducts = async (categories) => {
let productsRef = projectFirestore.collection("products");
let query = productsRef.where('category', 'in', categories);
query.get().then((querySnapshot) => {
let products = [];
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
products.push({
name: doc.data().name,
price: doc.data().price,
prev_price: doc.data().prev_price,
discount: doc.data().product_discount,
id: doc.id,
src: doc.data().pictures[0].src,
rating: doc.data().rating,
});
});
this.setState(() => {
return { products };
}, this.checkCartItems);
})
.catch(err => console.log(err));
};

i get two different values when i console.log the same array

I have a function that gets a product from my firstore database with the id.
when i console.log the array in the subscribe i get :
console.log(product[0]) -> Object { id: 0, quantity: 1, latinName: "stub", price: "10", name: "foo", }
console.log(product) -> [{ id: 0, quantity: 1, latinName: "stub", price: "10", name: "foo", }]
that's good and normal but when i do a console.log outside the subscribe.
Where i want to return the array i get different values.
then i get :
console.log(product[0]) -> undefined
console.log(product) -> [{ id: 0, quantity: 1, latinName: "stub", price: "10", name: "foo", }]
This is my code for getting the data and returning it
getProductfromDBByID(id: number): Observable<any> {
let product: Array<any> = [];
this.firestore
.collection('products', (ref) => ref.where('id', '==', id))
.get()
.subscribe((querySnapshot) => {
querySnapshot.forEach((doc) => {
product.push(doc.data());
console.log('product in subscribe ', product[0]);
});
});
console.log('product return value', product[0]);
return of(product);
}
That is because the console.log outside of the subscribe is executed before the subscribe is hit (asynchronous operation, request in this case).
To resolve that, move the actual subscription to the function that calls this function.
getProductfromDBByID(id: number): Observable<any> {
return this.firestore
.collection('products', (ref) => ref.where('id', '==', id))
.get();
}
...
product: Array<any>;
otherFunction() {
getProductfromDBByID(/*some id*/)
.subscribe((querySnapshot) => {
querySnapshot.forEach((doc) => {
this.product.push(doc.data());
});
});
}
Add "async" keyword before the function name and add "await" keyword before the future method which is the "this.firestore......"
async getProductfromDBByID(id: number): Observable<any> {
let product: Array<any> = [];
await this.firestore
.collection('products', (ref) => ref.where('id', '==', id))
.get()
.subscribe((querySnapshot) => {
querySnapshot.forEach((doc) => {
product.push(doc.data());
console.log('product in subscribe ', product[0]);
});
});
console.log('product return value', product[0]);
return of(product);
}

How to access data returning from an API Subscribe method outside in Angular

This is my angular code block.
demandCurveInfo = [];
ngOnInit() {
this.zone.runOutsideAngular(() => {
Promise.all([
import('#amcharts/amcharts4/core'),
import('#amcharts/amcharts4/charts'),
import('#amcharts/amcharts4/themes/animated'),
import('#amcharts/amcharts4/maps'),
import('#amcharts/amcharts4-geodata/worldLow'),
])
.then(modules => {
this.createDemandCurve(modules);
})
.catch(e => {
console.error('Error when creating chart', e);
});
});
}
This is where i am trying get API data.
async getDemandCurveInfo(statusType: string, valueType ) {
const params = [];
params.push({code: 'StreamCode', name: 'TG_PS'});
params.push({code: 'segmentCodes', name: ['US']});
params.push({code: 'checkinFrom', name: '2019-01-01'});
params.push({code: 'checkinTo', name: '2019-12-31'});
params.push({code: 'statusType', name: statusType});
params.push({code: 'valueType', name: valueType});
return await this.dashboardServiceHandler.getSegmentDemand([], params).toPromise();
}
Inside this function i am calling the above method.
createDemandCurve(modules: any) {
const am4core = modules[0];
const am4charts = modules[1];
const am4themesAnimated = modules[2].default;
this.getDemandCurveInfo('REAL', 'TTV').then((data) => {
this.demandCurveInfo.push(data.valueOf().data);
console.log(this.demandCurveInfo[0]); <- first
});
console.log(this.demandCurveInfo[0]); <- second
}
In here i am trying to get this.demandCurveInfo[0] data outside.But my second console.log gives output like undefined.First console.log gives output like this. How could i get the console.log data outside?.
You can introduce a new method to do that
this.getDemandCurveInfo('REAL', 'TTV').then((data) => {
this.demandCurveInfo.push(data.valueOf().data);
printData(this.demandCurveInfo[0]);
});
printData(data: string){
console.log(data);
}

About setState in React

Below is a function getting messages from firebase database, but it only setState to only one message.
However, the console.log can log multiple messages in the object.
Is there anything wrong in my function?
getMessages(){
var messages = [];
firebaseApp.database().ref('users/'+firebase.auth().currentUser.uid+'/userChat/'+firebase.auth().currentUser.uid).orderByValue().limitToLast(10).once('value', (dataSnapshot) => {
//alert(JSON.stringify(dataSnapshot.val()));
dataSnapshot.forEach((child) => {
firebaseApp.database().ref('messages').child(child.key).once("value", (message)=>{
//alert(JSON.stringify(messages));
messages.push({
_id: Math.round(Math.random() * 1000000),
text: message.val().text,
createdAt: new Date(message.val().timestamp),
user: {
_id: 1,
name: 'Developer',
},
});
this.setState({
messages: messages
});
console.log('woooo'+JSON.stringify(messages));
});
});
});
}
You are setting the state inside the forEach Block. try moving it outside the iteration block
As JanneKlouman mentioned it's not good enough to remove it from the iterration block as you are doing async calls.
You can create a new array and set it in the state on each iteration, react will batch those set state calls:
function getMessages() {
var messages = [];
firebaseApp.database().ref('users/' + firebase.auth().currentUser.uid + '/userChat/' + firebase.auth().currentUser.uid).orderByValue().limitToLast(10).once('value', (dataSnapshot) => {
//alert(JSON.stringify(dataSnapshot.val()));
dataSnapshot.forEach((child) => {
firebaseApp.database().ref('messages').child(child.key).once("value", (message) => {
const newMessage = {
_id: Math.round(Math.random() * 1000000),
text: message.val().text,
createdAt: new Date(message.val().timestamp),
user: {
_id: 1,
name: 'Developer',
},
}
const nextState = this.state.messages.map(message => {
return {
...message,
user: {...meesage.user} // i think we must do this in order to break out of the reference as spreading will only work on a shallow level
}
});
this.setState({
messages: [...nextState, newMessage]
});
});
});
});
}
Try cloning the array before setting state:
getMessages(){
let messages = [];
firebaseApp.database().ref('users/'+firebase.auth().currentUser.uid+'/userChat/'+firebase.auth().currentUser.uid).orderByValue().limitToLast(10).once('value', (dataSnapshot) => {
dataSnapshot.forEach((child) => {
firebaseApp.database().ref('messages').child(child.key).once("value", (message)=>{
const message = {
_id: Math.round(Math.random() * 1000000),
text: message.val().text,
createdAt: new Date(message.val().timestamp),
user: {
_id: 1,
name: 'Developer',
},
};
// Clone messages
messages = [...messages, message];
this.setState({ messages });
});
});
});
}

Mongoose/Mongo: Update Not Saving

I'm extremely perplexed by this issue that I'm having with mongo/mongoose. I'm essentially trying to get an array of products, delete a certain product from the array, and then update the shopping chart with the new array that omits the selected product. Here's the snippet of code I'm dealing with:
const remove = (req, res, next) => {
console.log('here is the product id ' + req.body.cart.product)
delete req.body._owner // disallow owner reassignment.
Cart.find({_id: req.user.cartId})
.then((products1) => {
console.log("array of products: " + products1[0].product)
const index = products1[0].product.indexOf(req.body.cart.product)
console.log("index valeu: " + index)
if (index > -1) {
products1[0].product.splice(index, 1)
return products1[0].product
}
return products1[0].product
})
.then((products2) => {
console.log('Second Promise Input: ' + products2)
Cart.update({_id: req.user.cartId}, {$set: {product: products2}})
})
.then(() => res.sendStatus(204))
.catch(next)
}
And here's the output from my server:
Server listening on port 4741
here is the product id 5952b57ea52d092b8d34c6b0
array of products: 5952b57ea52d092b8d34c6b0,5952b57ea52d092b8d34c6b0,5952b57ea52d092b8d34c6b0,5952b57ea52d092b8d34c6b0,5952b57ea52d092b8d34c6b0
index valeu: 0
Second Promise Input: 5952b57ea52d092b8d34c6b0,5952b57ea52d092b8d34c6b0,5952b57ea52d092b8d34c6b0,5952b57ea52d092b8d34c6b0
PATCH /carts-decrease/595b037e128cfd37e0c864d7 204 38.773 ms
According to my console.logs, I'm getting the array just the way I want it but it simply does not update the shopping cart with the new array. I've been staring at this code for far too long and I'd appreciate a second set of eyes on this. Thanks.
P.S. Ignore the fact that the product ids are all the same, its just a testing variable
Cart Schema:
'use strict'
const mongoose = require('mongoose')
const cartSchema = new mongoose.Schema({
product: {
type: Array,
required: false
},
owner: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
required: false
}
}, {
timestamps: true,
toJSON: {
virtuals: true,
transform: function (doc, ret, options) {
const userId = (options.user && options.user._id) || false
ret.editable = userId && userId.equals(doc._owner)
return ret
}
}
})
const Cart = mongoose.model('Cart', cartSchema)
module.exports = Cart
Product Schema:
'use strict'
const mongoose = require('mongoose')
const productSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
price: {
type: Number,
required: true
},
description: {
type: String,
required: true
}
}, {
toJSON: {
virtuals: true
}
})
const Product = mongoose.model('Product', productSchema)
module.exports = Product
Show request:
const show = (req, res) => {
const product = {}
product.array = []
// console.log(req.cart.product)
const promises = []
Promise.all(req.cart.product.map(function (id) {
return Product.find({_id: ObjectId(id)})
})).then(function (products) {
console.log(products)
req.cart.product = products
return res.json({
cart: req.cart.toJSON({virtuals: true, user: req.user})
})
}).catch(function (err) {
console.log(err)
return res.sendStatus(500)
})
}
I would recommend you to slightly modify your cartSchema and store products in the form of an array of embedded documents:
const cartSchema = new mongoose.Schema({
products: [{
name: { type: String },
price: { type: Number }
...
}]
...
});
If you do this you can simply use the $pull update operator to remove products from your cart:
{ $pull: { <field1>: <value|condition>, <field2>: <value|condition>, ... } }
In your case the query should then look like this:
Cart.update(
{ _id: req.user.cartId },
{ $pull: { products: { '_id': req.body.cart.product } }}
);
As the embedded documents will have their own ObjectId there will only be one document matching the query.

Resources