Im trying to figuring out why my firebase funtion for cheat is always creating but when like open the chat where it call create function immediately send a message the message will not be saved, because my function is not ready so how can I sole this?.
Heres my function .
export const onConversationCreated = functions.firestore.
document("Conversations/{conversationID}").onCreate((snapshot, context) => {
const data = snapshot.data();
const conversationID = context.params.conversationID;
if (data) {
const members = data.members;
for (let index = 0; index < members.length; index++) {
const uid = members[index];
const remainingUserIDs = members.filter((u: string) => u !== uid);
remainingUserIDs.forEach((m: string) => {
return admin.firestore().
collection("profile").doc(m).get().then((_doc) => {
const userData = _doc.data();
if (userData) {
return admin.firestore().collection("profile")
.doc(uid).collection("Conversations").doc(m).create({
"conversationID": conversationID,
"url": userData.url,
"name": userData.username,
"unseenCount": 0,
});
}
return null;
}).catch(() => {
return null;
});
});
}
}
return null;
});
export const onConversationUpdated = functions.firestore
.document("Conversations/{conversationID}").onUpdate((change, context) => {
const data = change?.after.data();
if (data) {
const members = data.members;
const lastMessage = data.messages[data.messages.length - 1];
for (let index = 0; index < members.length; index++) {
const uid = members[index];
const remainingUserIDs = members.filter((u: string) => u !== uid);
remainingUserIDs.forEach((u: string) => {
return admin.firestore().collection("meinprofilsettings")
.doc(uid).collection("Conversation").doc(u).update({
"lastMessage": lastMessage.message,
"timestamp": lastMessage.timestamp,
"type": lastMessage.type,
"lastmessageuid": lastMessage.senderID,
"unseenCount": admin.firestore.FieldValue.increment(1),
});
});
}
}
return null;
});
So again creating is correct working. its just need some time . And when I immediately when calling create function write a message and send it this message will not be saved until the create function is finished then I have to send again the message
enter image description here
The reason for your bug is that you don't await the execution of your async task correctly. Unfortunately the forEach doesn't support async so we need to revrite your code to something like this:
export const onConversationCreated = functions.firestore
.document("Conversations/{conversationID}")
.onCreate((snapshot, context) => {
const data = snapshot.data();
const promises: Promise<any>[] = [];
const conversationID = context.params.conversationID;
if (data) {
const members = data.members;
for (let index = 0; index < members.length; index++) {
const uid = members[index];
const remainingUserIDs = members.filter((u: string) => u !== uid);
remainingUserIDs.forEach((m: string) => {
promises.push(
admin
.firestore()
.collection("profile")
.doc(m)
.get()
.then((_doc) => {
const userData = _doc.data();
if (userData) {
return admin
.firestore()
.collection("profile")
.doc(uid)
.collection("Conversations")
.doc(m)
.create({
conversationID: conversationID,
url: userData.url,
name: userData.username,
unseenCount: 0,
});
}
return null;
})
);
});
}
}
return Promise.all(promises);
});
export const onConversationUpdated = functions.firestore
.document("Conversations/{conversationID}")
.onUpdate((change, context) => {
const data = change?.after.data();
const promises: Promise<any>[] = [];
if (data) {
const members = data.members;
const lastMessage = data.messages[data.messages.length - 1];
for (let index = 0; index < members.length; index++) {
const uid = members[index];
const remainingUserIDs = members.filter((u: string) => u !== uid);
remainingUserIDs.forEach((u: string) => {
promises.push(
admin
.firestore()
.collection("meinprofilsettings")
.doc(uid)
.collection("Conversation")
.doc(u)
.update({
lastMessage: lastMessage.message,
timestamp: lastMessage.timestamp,
type: lastMessage.type,
lastmessageuid: lastMessage.senderID,
unseenCount: admin.firestore.FieldValue.increment(1),
})
);
});
}
}
return Promise.all(promises);
});
We use Promise.all() to even run all your async tasks in parallel to finish the function faster and save on execution time.
Related
This code is not working for me i am trying to pull data from my mongodb
const ProductScreen = ({ match }) => {
const [product, setProduct] = useState({});
const { id } = useParams();
useEffect(() => {
const fetchProduct = async () => {
const { data } = await axios.get(
`/api/product/${encodeURIComponent(id)}`
);
setProduct(data);
};
fetchProduct();
}, []);
};
pull data from server of mongo db
It is possible when the component first mounts, id is null and useParams() doesn't get it till the second render. So add an if statement in your useEffect to make sure the id is present. Also add id to the dependency array, so if the id changes, you will refetch the data for it. Otherwise, with an empty dependency array, the useEffect will only run on first mount.
const ProductScreen = ({ match }) => {
const [product, setProduct] = useState({});
const { id } = useParams();
useEffect(() => {
const fetchProduct = async () => {
const { data } = await axios.get(
`/api/product/${encodeURIComponent(id)}`
);
setProduct(data);
};
if (id) {
fetchProduct();
}
}, [id]);
};
Working on beginner steps toward vue 3 and firestore migration. Stuck on simple.
import { getUsersCount } from "/src/firebase";
setup() {
const usersCount = getUsersCount();
return {
usersCount,
};
},
Why it returns Promise Object, I cant find in manuals.
export const getUsersCount = async () => {
// const querySnap = await getDocs(query(collection(db, "users")));
const q = query(collection(db, "users"));
const unsub = onSnapshot(q, (querySnapshot) => {
console.log("usersCount33: ", querySnapshot.size);
//unsub();
return querySnapshot.size;
});
}
Nad the last part with template,
<template>
<p>Users Count: {{ usersCount }}</p>
</template>
If you return the value inside a callback, you can not use async await syntax. You should do this:
export const getUsersCount = () => {
return new Promise((resolve, reject) => {
const q = query(collection(db, "users"));
const unsub = onSnapshot(q, (querySnapshot) => {
return resolve(querySnapshot.size)
});
})
}
// You still need to wait getUsersCount when using it
const usersCount = await getUsersCount();
I was writing a couple of tests to my test database but I can't seem to save a document('add user to database' test) . When I run the test I get the correct length of the number of users but when I actually go to the database I only see one user document(firstUser) and cannot see the newUser document. I think it is an issue with the beforeEach function as when I remove it, everything works with the only issue being the same user being repeatedly added to the database when the test is run.
Test Code
const supertest = require('supertest')
const mongoose = require('mongoose')
const app = require('../app')
const User = require('../models/user')
const bcrypt = require('bcrypt')
const api = supertest(app)
beforeEach(async () => {
await User.deleteMany({})
const passwordHash = await bcrypt.hash('12345',10)
const firstUser = new User(
{
username: "Big Mark",
password: passwordHash,
name:"Mark"
}
)
await firstUser.save()
})
describe('user tests', () => {
// Cannot see this document in mongoDB
test('add user to database', async () => {
const newUser = {
username: 'smart',
password: 'dvsgfd',
name: 'Kevin'
}
const result = await api.post('/api/users').send(newUser).expect(201)
const length = await api.get('/api/users')
expect(length._body).toHaveLength(2)
console.log("length is", length)
})
test('see if fetching works', async () => {
const fetchedUsers = await api.get('/api/users').expect(201)
})
// test('returns 404 error if username already exists', async () => {
// })
})
afterAll(() => {
mongoose.connection.close()
},100000)
Router Code
const userRouter = require('express').Router()
const User = require('../models/user')
const bcrypt = require('bcrypt')
userRouter.post('/', async (request,response) => {
console.log("request body is", request.body)
const {username,password,name} = request.body
const alreadyThere = await User.findOne({username})
if(alreadyThere == null && username.length > 2 && password.length > 2) {
const saltRounds = 10 //How many times password it gonna get hashed (Ex: 2^n times)
const passwordHash = await bcrypt.hash(password,saltRounds)
const user = new User(
{
username,
password: passwordHash,
name
}
)
const savedUser = await user.save()
console.log("SavedUser is", savedUser)
response.status(201).json({savedUser})
}
else {
response.status(404).json({error: "Username must be unique"})
}
})
userRouter.get('/', async(request,response) => {
const users = await User.find({})
response.status(201).json(users)
})
module.exports = userRouter
I am trying to fetch data from MongoDB, but apparently, it gives an error
FetchError: invalid json response body at
http://localhost:3000/api/products/6092ca3460fc67315178f2fa reason: Unexpected token < in JSON at position 0
const defaultEndpoint = 'http://localhost:3000/api/products/';
export const getStaticPaths = async () => {
const res = await fetch(defaultEndpoint);
const data = await res.json();
const paths = data.map (product => {
return {
params: { id: product._id.toString() }
}
})
return {
paths,
fallback: false
}
}
export const getStaticProps = async (context) => {
const id = context.params.id;
const res = await fetch ('http://localhost:3000/api/products/' + id);
const data = await res.json ();
return {
props: {product: data}
}
}
const Details = ({product}) => {
return (
<div>
<h1>{product.title}</h1>
</div>
)
}
export default Details
API Endpoint which is perfectly working on http://localhost:3000/api/products
import { connectToDatabase } from "../../util/mongodb";
export default async (req, res) => {
const { db } = await connectToDatabase();
const products = await db.collection("products").find({}).toArray();
res.json(products);
};
I am using drag and drop library to change the order of my elements, and I need that order to be saved, the following method does change the document but it won't save it, I tried doc.save() and this update method, the logged doc is in changed order but it's not updated in the database.
module.exports.changeListOrder = async(req, res) => {
const { id, listID, oldIndex, newIndex } = req.body;
await Board.findById(id).then(async(doc) => {
let tmpdoc = doc.lists[oldIndex];
doc.lists[oldIndex] = doc.lists[newIndex];
doc.lists[newIndex] = tmpdoc;
await Board.updateOne({ _id: id }, { $set: { list: doc.lists } })
});
}
and my model has
lists: [{ header: String, listItems: Array }]
You are mixing up Promise and async syntax. The async syntax would be like this:
module.exports.changeListOrder = async (req, res) => {
const { id, listID, oldIndex, newIndex } = req.body;
const thisBoard = await Board.findById(id);
// this code won't run until thisBoard has returned a value
let [oldValue, newValue] = [thisBoard.lists[oldIndex], thisBoard.lists[newIndex];
thisBoard[oldIndex] = newValue;
thisBoard[newIndex] = oldValue;
let saveOperation = await Board.save(thisBoard);
// console.log(saveOperation);
// return saveOperation or do something with res()
};
module.exports.changeListOrder = async(req, res) => {
const { id, listID, oldIndex, newIndex } = req.body;
const doc = await Board.findById(id);
let [oldValue, newValue] = [doc.lists[oldIndex], doc.lists[newIndex]];
doc.lists.set(oldIndex, newValue);
doc.lists.set(newIndex, oldValue);
await doc.save();
};
Here is the working code, the problem was that Mongoose doesn't create getters/setters for array indexes; without them mongoose never gets notified of the change and so doesn't know to persist the new value, so you have to use set()