I declared a global array in index.js (firebase function). Once the code is deployed, this array is filled from firebase data.
I have two functions, in the first one (onTW) i made some changes to the array, and i'm just displaying it in the other function(onRemoveTW). The problem is I'm getting an empty array in the second function.
Here's my code.
var TWArray = [];
TWRef.once('value', function (snapshot) {
snapshot.forEach(function(childSnapshot) {
var name=childSnapshot.key;
var users = {};
var userNbr = 0;
TWRef.child(name).child('rm').once('value', function (snapshot2) {
snapshot2.forEach(function(childSnapshot2) {
userNbr++;
if(childSnapshot2.key=='a'){
users.a = childSnapshot2.val();
}
if(childSnapshot2.key=='b'){
users.b = childSnapshot2.val();
}
if(childSnapshot2.key=='c'){
users.c = childSnapshot2.val();
}
if(childSnapshot2.key=='d'){
users.d = childSnapshot2.val();
}
})
TWArray.push({
rmName:name,
users:users,
userNbr:userNbr
});
})
})
})
exports.onTW = functions.database
.ref('/Orders/TW/{requestId}')
.onWrite(event => {
const userKey = event.data.key;
const post = event.data.val();
if (post != null) {
var users={};
users.a=userKey;
TWArray.push({
rmName:userKey,
users:users,
userNbr:1
});
console.log(TWArray);
console.log("TWArray.length : "+TWArray.length);
}
});
exports.onRemoveTW = functions.database
.ref('/Orders/RemoveTW/{requestId}')
.onWrite(event => {
const userKey = event.data.key;
const post = event.data.val();
if (post != null) {
console.log("TWArray.length : "+TWArray.length);
}
})
Thanks in advance!
You cannot share data between functions by writing to global variables when using firebase-functions, because they intended to be stateless. As such, this functionality is not supported.
What you can do is write your data to firebase-database instead.
Related
I am trying to alter a object variable after query in cloud functions, but before sending it to my app, but not sure how to do so! Here is what I am trying to do:
Parse.Cloud.define("getUserData", async(request) => {
// Getting the users data
const userQuery = new Parse.Query("UserData");
userQuery.equalTo("userId", request.params.userId);
const userData = await userQuery.first();
// Getting the groups
const groupQuery = new Parse.Query("GroupMembers");
groupQuery.equalTo("userId", request.params.userId);
groupQuery.include('pointerObject'); // including the pointer object
const groups = await groupQuery.find();
const allGroups = [];
for (let i = 0; i < groups.length; ++i) {
var thisGroup = groups[i].get("pointerObject");
thisGroup.isFavorite = true;
allGroups.push(thisGroup);
}
var returnObject = {
"playerData": userData,
"playerGroups": allGroups
}
const jsonString = JSON.stringify(returnObject);
return jsonString;
});
It is "thisGroup.isFavorite" i am trying to set to true, but when receiving the jsonString, it is still set to false? How do I alter a variable in cloud functions?
Any help is appreciated and thanks in advance :-)
Try with:
thisGroup.set('isFavorite', true);
await thisGroup.save();
The problem is that every time I click on an element with a state things appear twice. For example if i click on a button and the result of clicking would be to output something in the console, it would output 2 times. However in this case, whenever I click a function is executed twice.
The code:
const getfiles = async () => {
let a = await documentSpecifics;
for(let i = 0; i < a.length; i++) {
var wrt = document.querySelectorAll("#writeto");
var fd = document.querySelector('.filtered-docs');
var newResultEl = document.createElement('div');
var writeToEl = document.createElement('p');
newResultEl.classList.add("result");
writeToEl.id = "writeto";
newResultEl.appendChild(writeToEl);
fd.appendChild(newResultEl);
listOfNodes.push(writeToEl);
listOfContainers.push(newResultEl);
wrt[i].textContent = a[i].data.documentName;
}
}
The code here is supposed to create a new div element with a paragraph tag and getting data from firebase firestore, will write to the p tag the data. Now if there are for example 9 documents in firestore and i click a button then 9 more divs will be replicated. Now in total there are 18 divs and only 9 containing actual data while the rest are just blank. It continues to create 9 more divs every click.
I'm also aware of React.Strictmode doing this for some debugging but I made sure to take it out and still got the same results.
Firebase code:
//put data in firebase
createFileToDb = () => {
var docName = document.getElementById("title-custom").value; //get values
var specifiedWidth = document.getElementById("doc-width").value;
var specifiedHeight = document.getElementById("doc-height").value;
var colorType = document.getElementById("select-color").value;
parseInt(specifiedWidth); //transform strings to integers
parseInt(specifiedHeight);
firebase.firestore().collection("documents")
.doc(firebase.auth().currentUser.uid)
.collection("userDocs")
.add({
documentName: docName,
width: Number(specifiedWidth), //firebase-firestore method for converting the type of value in the firestore databse
height: Number(specifiedHeight),
docColorType: colorType,
creation: firebase.firestore.FieldValue.serverTimestamp() // it is possible that this is necessary in order to use "orderBy" when getting data
}).then(() => {
console.log("file in database");
}).catch(() => {
console.log("failed");
})
}
//get data
GetData = () => {
return firebase.firestore()
.collection("documents")
.doc(firebase.auth().currentUser.uid)
.collection("userDocs")
.orderBy("creation", "asc")
.get()
.then((doc) => {
let custom = doc.docs.map((document) => {
var data = document.data();
var id = document.id;
return { id, data }
})
return custom;
}).catch((err) => {console.error(err)});
}
waitForData = async () => {
let result = await this.GetData();
return result;
}
//in render
let documentSpecifics = this.waitForData().then((response) => response)
.then((u) => {
if(u.length > 0) {
for(let i = 0; i < u.length; i++) {
try {
//
} catch(error) {
console.log(error);
}
}
}
return u;
});
Edit: firebase auth is functioning fine so i dont think it has anything to do with the problem
Edit: This is all in a class component
Edit: Clicking a button calls the function createFileToDb
I think that i found the answer to my problem.
Basically, since this is a class component I took things out of the render and put some console.log statements to see what was happening. what i noticed is that it logs twice in render but not outside of it. So i took the functions out.
Here is the code that seems to fix my issue:
contain = () => {
const documentSpecifics = this.waitForData().then((response) => {
var wrt = document.getElementsByClassName('writeto');
for(let i = 0; i < response.length; i++) {
this.setNewFile();
wrt[i].textContent = response[i].data.documentName;
}
return response;
})
this.setState({
docs: documentSpecifics,
docDisplayType: !this.state.docDisplayType
})
}
As for creating elements i put them in a function so i coud reuse it:
setNewFile = () => {
const wrt = document.querySelector(".writeto");
const fd = document.querySelector("#filtered-docs");
var newResultEl = document.createElement('div');
newResultEl.classList.add("result");
var wrtEl = document.createElement('p');
wrtEl.classList.add("writeto");
fd.appendChild(newResultEl);
newResultEl.appendChild(wrtEl);
}
The firebase and firestore code remains the same.
the functions are called through elements in the return using onClick.
This is a socket.io lobby library for managing the users list.
I created an Array extension class with custom methods. My removeUser method does not work.
Logging shows that inside of the method, it does work - the user has been removed.
Logging outside shows no change.
I believe my issue is one of references. The reference in index.js 'userList' is one reference.
var userList = require("./userList")();
However when I reassign userList in the method, it creates another reference.
userArray = result;
This newly-created reference is not known by the index.js, which sees no change in the userList object.
index.js
My server (simplified for example)
const express = require("express");
const bodyParser = require("body-parser");
const app = express();
const server = require("http").createServer(app);
const io = require("socket.io")(server);
var userList = require("./userList")();
io.on("connection", (socket) => {
// get user from session
userList.addUser(s_user);
socket.on("disconnect", () => {
userList.removeUser(s_user);
});
});
userList.js (Original)
An extended Array class for managing the list of users in my lobby.
function createUserList() {
let userArray = [];
userArray.addUser = (user) => {
userArray.push(user);
};
userArray.removeUser = (user) => {
let userId = user.user_id;
for (let i = 0; i < userArray.length; i++) {
if (userArray[i]["user_id"] === userId && userId !== undefined) {
let firstHalf = userArray.slice(0, i);
let secondHalf = userArray.slice(i+1, userArray.length);
let result = firstHalf.concat(secondHalf);
userArray = result;
}
}
};
return userArray;
}
My Solution
My solution was to create a closure. An array manager object contains the methods for userList management, and through a closure has access to the userArray. (code below this paragraph)
Pros
The userArray can modified or reassigned without reference issue (within the userList library)
userArray = [] //ok
(I also don't have to re-attach methods on re-assignment)
Cons
I can't use Array prototype methods
let length = userList.length // method doesn't exist on management object
let listCopy = userList // returns an object, not the list
I must use my custom built methods
let length = userList.getLength()
let listCopy = userList.getList()
Does anyone have other interesting solutions?
userList.js (V2)
function createUserList() {
let userArray = []
let arrayManager = {
addUser: (user) => {
userArray.push(user);
},
removeUser: (user) => {
let userId = user.user_id;
for (let i = 0; i < userArray.length; i++) {
if (userArray[i]["user_id"] === userId && userId !== undefined) {
let firstHalf = userArray.slice(0, i);
let secondHalf = userArray.slice(i+1, userArray.length);
let result = firstHalf.concat(secondHalf);
userArray = result;
}
}
},
getList: () => {
return userArray;
},
getLength: () => {
return userArray.length;
}
};
return arrayManager;
}
module.exports = createUserList;
Coming across something i thought would have worked, but does not.
I have the following function that takes an input and needs to update one value in the mongodb.
const updateSkillXP = (data) =>{
//data = { username:username, sk:sk, xp:100 }
const collection = db.collection('player');
let q = {username:data.username}
//craft a key depending on what skill code comes through.
let s = "skills."+data.sk;
u = {$set: {s : data.xp}}
return collection.updateOne(q,u,(err,res) =>{
if(err) console.log(err);
})
}
The MongoDB document looks as follows
player = {
x:0,
y:0,
username:"foo",
skills : { //I need one of the following to update.
atk:0,
str:0,
def:0,
hp:0
}
}
When I executed the above, it added 'S' Property, but i was expecting to change the value of say 'atk' to what ever xp came through?
Answer:
JavaScript set object key by variable
const updateSkillXP = (data) =>{
//data = { username:username, sk:sk, xp:100 }
const collection = db.collection('player');
let q = {username:data.username}
let s = "skills."+data.sk;
let obj = {};
obj[s] = data.xp;
u = {$set: obj}
return collection.updateOne(q,u,(err,res) =>{
if(err) console.log(err);
})
}
I have a route that sends to me many requests over time, that contain data to stored in a model.
So the first request does not contain all the needed data and I need to parse each request every time new information comes and store it.
Actually I have a separate js file which contains the "model" and methods
const request = require('request-promise');
function Conversation(param) {
console.log(param)
this.endpoint ;
this.id = this.getConvId(param);
this.createdOn = Date.now();
this.to = this.getTo(param);
this.from = this.getFrom(param);
this.state = this.getState(param);
this.importance = this.getImportance(param);
this.threadId = this.getT;
this.subject = this.getSubject(param);
this.name=this.getName(param);
}
Conversation.prototype.sendIM =function sendIM(param) {
// method to send message to a user
}
Conversation.prototype.getConvId = function getConvId(param) {
return param.operationId
};
Conversation.prototype.getTo = function getTo(param) {
return param.to
}
Conversation.prototype.getDirection = function getDirection(param) {
return param.direction
}
Conversation.prototype.getState = function getState(param) {
return param.state
}
Conversation.prototype.getOperationId = function getOperationId(param) {
return param.sender[0].events[0]._embedded["service:messagingInvitation"].opertionId
}
Conversation.prototype.getImportance = function getSubject(param) {
return param.importance;
}
Conversation.prototype.getSubject = function getSubject(param) {
return param.sender[0].events[0]._embedded["service:messagingInvitation"].subject
}
Conversation.prototype.getFrom= function getFrom(param) {
return param._embedded["localParticipant"].uri
}
Conversation.prototype.getName= function getName(param) {
return param._embedded["acceptedByParticipant"].name
}
module.exports = Conversation;
In my main app file I create a new conversation object:
var Conversation= require('./Conversation');
app.post('/callback', function (req, res) {
if(req.body.sender.length==0) {
res.status(200).send();
}
if(req.body.sender.length>0) {
const conv = new Conversation(req.body.sender[0].events[0]._embedded['service:messagingInvitation']);
res.status(200).send();
}
})
the method works well when I have to fill the model once, but when I update an item it becomes complicated.
So I would like to know what is the best way to structure my files so that I will be able to add new data to my model over time ?