Firebase issue, I need to take out values from first two nodes - javascript

I try to achieve the following: When count is changed to "2" I need the function to push the JSON, named "updates", to the specific place in database, and take names from PlayerQueue node (0:"Mik", 1:"Bg" etc.) and put it into the database as "id". So the thing is that I need it to take first two nodes (0 and 1 in this case) and take names out of it (Mik and Bg) and put them in the database as id1 and id2 (in this database I have only one id value but I will add it later), the issue is that I can't figure out how to take out names from the first two nodes.
My database:
And here is my code
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
import { resolve } from 'url';
//Game/queue/{queueId}/PlayerCount
admin.initializeApp(functions.config().firebase);
exports.createGame = functions.database.ref('Game/queue/PlayerCount').onUpdate((change, context) => {
const ref1 = admin.database().ref('/Game/queue/PlayerQueue').limitToFirst(1);
var tmp:String = 'esh';
ref1.once("value")
.then(result => {
tmp = result.val();
console.log(tmp)
var updates = {};
updates['id'] = tmp
updates['visible'] = {
place: 'a1',
sign: 'rock'
};
const after = change.after.val();
if(after.count == 2){
return admin.database().ref('/Game/allGames').push(updates);
}
return null
}).catch(reason => {
console.log(reason)
});
return null;
});

Since you're looking for the first two child nodes in the queue, you should order by their ID and then limit to getting 2 children:
const query = admin.database().ref('/Game/queue/PlayerQueue').orderByKey().limitToFirst(2);
Then you can listen for the value:
query.once("value").then(snapshot => {
snapshot.forEach(child => {
console.log(child.key+": "+child.val());
});
});
The above purely solves the "getting the first two child nodes".
Update: to get the two children into separate variables, you can do something like this:
query.once("value").then(snapshot => {
var first, second;
snapshot.forEach(child => {
console.log(child.key+": "+child.val());
if (!first) {
first = child.val();
}
else if (!second) {
second = child.val();
}
});
if (first && second) {
// TODO: do something with first and second
}
});

Use Firestore unless you have a valid reason to use the Realtime Database.
See Cloud Firestore triggers documentation on how to take action .onUpdate to qty 2. See documentation example below
exports.updateUser = functions.firestore
.document('users/{userId}')
.onUpdate((change, context) => {
// Get an object representing the document
// e.g. {'name': 'Marie', 'age': 66}
const newValue = change.after.data();
// ...or the previous value before this update
const previousValue = change.before.data();
// access a particular field as you would any JS property
const name = newValue.name;
// perform desired operations ...
});

Related

How to chain filter and map methods in nodejs?

So I'm working on a project where I'm making a call to a database to retrieve the data stored there. This data comes as an array. here is the code:
const allLogins = await Login.find().sort("name");
const token = req.header("x-auth-token");
const user = jwt.verify(token, config.get("jwtPrivateKey"));
const logins = allLogins
.filter((login) => login.userId === user._id)
.map((login) => {
login.password = decrypt(login.password);
});
If I call a console.log after the decrypt has been run I see that it has been completed correctly. The issue I have is if I console.log(logins) it says it is an array of two items that are both undefined. If instead I run it like this...
const allLogins = await Login.find().sort("name");
const token = req.header("x-auth-token");
const user = jwt.verify(token, config.get("jwtPrivateKey"));
let logins = allLogins.filter((login) => login.userId === user._id);
logins.map((login) => {
login.password = decrypt(login.password);
});
Then it works as it should. I'm not sure why the first set of code doesn't work and why the second set does work.
Any help would be appreciated!
Basic :
array. filter - accept a callback and call back return boolean (that match our criteria)
array.map - accept a callback and call back return transformed object
In the second working example:
logins.map((login) => {
// note: logins is iterated but not assigned to logins back
// so accessing login is working
login.password = decrypt(login.password); // map should return data
+ return login; // if we update all code will work
});
Now coming to first example:
const logins = allLogins
.filter((login) => login.userId === user._id)
.map((login) => {
login.password = decrypt(login.password);
+ return login; // this will fix the issue
});

Updating multiple objects in an Array belonging to a collection

I'm using MERN stack for my program with mongoose for accessing the database. I have a collection called Movies and I wanted to edit multiple objects in an array within this collection. This is what the Movie Schema contains in my database:
I wanted to edit multiple objects in the 2D array within seats and to change isReserved to True.
I just used findOne in accessing the data since I still don't know how to update the objects that I want to access.
app.post('/confirm/:movieId/:timeId', (req, res) => {
const movieId = req.params.movieId;
const timeId = req.params.timeId;
const selectedSeats = req.body;
// console.log("in confirm DB ");
// console.log(selectedSeats);
let getSeats;
let getTimeSlots;
const length_timeId = timeId.length;
Movies.findOne({ movieId }, (err, movie) => {
console.log("INSIDE");
getTimeSlots = movie['timeslots'];
let index = timeId.substring(1, length_timeId);
//get the seats
getSeats = getTimeSlots[parseInt(index)-1];
//loop through seats
console.log("PRINTING GET SEATS");
console.log(getSeats);
for(var i=0; i<selectedSeats.length; i++) {
let row = parseInt(selectedSeats[i] / 5);
let id = selectedSeats[i] % 5;
console.log(getSeats["seats"][row][id]);
}
})
})
I already accessed the objects that I want to edit as that code displays this on my terminal:
Would really appreciate some tips on how to update the isReserved status. Thanks!
Do you specify the timeslot and seat by an id or by the index within the array? If you use the index then solution is quite simple
const key = "timeslots." + req.params.timeId + ".seats." + req.body + ".isReserved";
var upd = {};
upd[key] = true;
db.Movies.updateOne({ movieId: req.params.movieId }, { $set: upd })
If your code uses the id then you have to work with array filters, see Update Nested Arrays in Conjunction with $[], so similar to this
db.Movies.updateOne(
{ movieId: req.params.movieId },
{ $set: { "timeslots.$[slot].seats.$[seat].isReserved": true } },
{ arrayFilters: [ { "slot.id": req.params.timeId } , { "seat.id": req.body } ] }
)

Is it possible to set limit for array in firestore?

i am planning to create an array of only 5 elements max in firestore like this
Array a = [1,2,3,4,5]
then add element 6 it will look like this
Array a = [2,3,4,5,6]
This cloud function (found here: https://github.com/firebase/functions-samples/blob/master/limit-children/functions/index.js) does what you want in Realtime Database:
'use strict';
const functions = require('firebase-functions');
// Max number of lines of the chat history.
const MAX_LOG_COUNT = 5;
// Removes siblings of the node that element that triggered the function if there are more than MAX_LOG_COUNT.
// In this example we'll keep the max number of chat message history to MAX_LOG_COUNT.
exports.truncate = functions.database.ref('/chat').onWrite((change) => {
const parentRef = change.after.ref;
const snapshot = change.after
if (snapshot.numChildren() >= MAX_LOG_COUNT) {
let childCount = 0;
const updates = {};
snapshot.forEach((child) => {
if (++childCount <= snapshot.numChildren() - MAX_LOG_COUNT) {
updates[child.key] = null;
}
});
// Update the parent. This effectively removes the extra children.
return parentRef.update(updates);
}
return null;
});
I believe you can adapt it for Firestore.

only one object being set to app.set() Expressjs

Good Afternoon,
I am using the MERN stack to making a simple invoice application.
I have a function that runs 2 forEach() that goes through the invoices in the DB and the Users. if the emails match then it gives the invoices for that user.
When I log DBElement to the console it works, it has the proper data, but when I log test1 to the console (app.get()) it only has one object not both.
// forEach() function
function matchUserAndInvoice(dbInvoices, dbUsers) {
dbInvoices.forEach((DBElement) => {
dbUsers.forEach((userElement) => {
if(DBElement.customer_email === userElement.email){
const arrayNew = [DBElement];
arrayNew.push(DBElement);
app.set('test', arrayNew);
}
})
})
}
// end point that triggers the function and uses the data.
app.get('/test', async (req,res) => {
const invoices = app.get('Invoices');
const users = await fetchUsersFromDB().catch((e) => {console.log(e)});
matchUserAndInvoice(invoices,users,res);
const test1 = await app.get('test');
console.log(test1);
res.json(test1);
})
function matchUserAndInvoice(dbInvoices, dbUsers) {
let newArray = [];
dbInvoices.forEach((DBElement) => {
dbUsers.forEach(async(userElement) => {
if(DBElement.customer_email === userElement.email){
newArray.push(DBElement);
app.set('test', newArray);
}
})
})
}
app.set('test', DBElement); overrides the existing DBElement, so only the last matching DBElement is shown in test1.
If you want to have test correspond to all matching DBElement, you should set it to an array, and then append a new DBElement to the array each time it matches inside the for-loop:
if(DBElement.customer_email === userElement.email){
let newArray = await app.get('test');
newArray.push(DBElement);
app.set('test', newArray);
}

How can I check if there's an object with a same key and update with a same key and different properties in array(javascript)?

Hi I'm working on a react project using Socket.io
On client side, it updates when an user click a different button with an Object such as
var actionArray, setActionArray
[actionArray, setActionArray] = React.useState({})
setActionArray({key: "rgb(211,40,21)", gesture: "🤘"})
As the user click a different button, only the gesture property changes.
On server side, several users will update their gesture simultaneously, and the color is used as key value to recognize different users. I want to accumulate the objects with different key in this 'colorArray' array, and update only the 'gesture' property when the user update their 'gesture' value with the same key property.
var colorArray = [];
socket.on("action", data => {
notifySubscribers(data);
console.log(data);
if (data.actionArray) {
colorArray.push({
key: data.actionArray.key,
id: id,
gesture: data.actionArray.gesture
});
subscribers.forEach(socket =>
socket.emit("colorArray", { colorArray: colorArray })
);
console.log(colorArray);
}
With the code above, it keeps adding new objects with same key value, but how can I update the object with same key with different 'gesture' property?
Here's some of the methods I tried, and didn't work.
//1
colorArray = colorArray.filter(item => item.key !== data.actionArray.key);
//2
let updatedItem = colorArray.find(element => {
return element.key === colorArray.key;
});
updatedItem.gesture = data.actionArray.gesture;
You were getting close, try this.
if (data.actionArray) {
let matchIndex = colorArray.findIndex(element => {
return element.key === data.actionArray.key
});
updatedItem = {
...data.actionArray,
id: id,
};
if (matchIndex > -1) {
colorArray[matchIndex] = updatedItem;
} else {
colorArray.push(updatedItem);
}
subscribers.forEach(socket =>
socket.emit("colorArray", { colorArray: colorArray })
);
console.log(colorArray);
}

Categories