Firebase Cloud Function To Sum up or aggregate values - firebase

I have been trying to sum up the price to bring up a total through the new firebase cloud functions
"Cart" : {
"-Ksdasd50oR04q073k5" : {
"ID" : 0.01,
"price" : 20
},
"-KhOc0CGdsddihGB2N" : {
"ID" : 001,,
"price" : 20
},
This is my start ,
exports.cartadd = functions.database.ref('Cart/{uid}').onWrite(event => {
let ref = admin.database().ref('Cart/{uid}');
return ref.once('value').then(snapshot => {
if (snapshot.hasChildren()) {
var total= 0;
snapshot.forEach(function(child) {
total += snapshot.val().price;
});
console.log(total);
}
});

This should do it:
exports.cartadd = functions.database.ref('Cart').onWrite(event => {
const snapshot = event.data;
if (snapshot.hasChildren()) {
var total= 0;
snapshot.forEach(function(item) {
total += item.child('price').val();
});
console.log(total);
}
});

Try this:
exports.cartadd = functions.database.ref('Cart').onWrite(event => {
const snapshot = event.data;
const totalRef = admin.database().ref("Cart/total");
if (snapshot.hasChildren()) {
let total= 0;
snapshot.forEach(function(item) {
total += item.child('price').val();
});
const transaction = totalRef.set(total).then(()=>{console.log(total);});
return Promise.all([transaction]);
}
});

Since the total needs to change, it should be a var not const.
Change
const total = 0;
to
var total = 0;

total += child.val().price; // instead

Related

Properly Reading Firebase data, using it, and Writing using React Native

I'm trying to utilize my Google firebase to hold data such a equipment details, work details, and work orders. The idea I had was to hold it all on firebase firestore. In react-native, I wanted to be able to use a separate function file to be able to access the data on firebase, then process it, and then write new information on the firestore. I'm having a bit of trouble temporarily saving the data in an array using the async function with push, and being able to regularly use that information for a variety of functions. The code below just results with too many promises exceptions. Is there a better way to write a script? Or, do you have a way to be able to simplify this?
import firestore from '#react-native-firebase/firestore';
class Worker {
constructor(name, certifications, shift, location) {
this.name = name;
this.certifications = certifications;
this.shift = shift;
this.location = location;
this.currentPosition = location;
this.timeLeftinShift = 8;
this.schedule = [];
this.doneScheduling = false;
}
}
class WorkOrder {
constructor(
eID,
eType,
facility,
location,
priority,
timeStamp,
timeToComplete,
) {
this.eID = eID;
this.eType = eType;
this.facility = facility;
this.location = location;
this.priority = priority;
this.timeStamp = timeStamp;
this.timeToComplete = timeToComplete;
this.done = false;
}
}
class Facility {
constructor(name, location, maxOcc) {
this.name = name;
this.location = location;
this.maxOcc = maxOcc;
this.curOcc = 0;
}
}
//assigns a worker
export function assignWorker() {
var tempWorkers = [];
async function workers() {
const workersCollection = await firestore()
.collection('workers')
.get()
.then(async (querySnapshot) => {
querySnapshot.forEach(async (documentSnapshot) => {
let temp = new Worker(
documentSnapshot.id,
documentSnapshot.data().Certifications,
documentSnapshot.data().Shift,
[
documentSnapshot.data().Location.longitude,
documentSnapshot.data().Location.latitude,
],
);
tempWorkers.push(temp);
});
});
return tempWorkers;
}
var tempFacilities = [];
async function Facilities() {
var tempFacilities = [];
const facilitiesCollection = await firestore()
.collection('facility')
.get()
.then(async (querySnapshot) => {
querySnapshot.forEach(async (documentSnapshot) => {
let temp = new Facility(
documentSnapshot.id,
[
documentSnapshot.data().Location.longitude,
documentSnapshot.data().Location.latitude,
],
documentSnapshot.data()['Max Occupancy'],
);
tempFacilities.push(temp);
});
});
return tempFacilities;
}
var tempWorkOrders = [];
async function workOrders() {
var tempWorkOrders = [];
const workOrdersCollection = await firestore()
.collection('sample work order')
.get()
.then(async (querySnapshot) => {
querySnapshot.forEach(async (documentSnapshot) => {
let temp = new WorkOrder(
documentSnapshot.data()['Equipment ID'],
documentSnapshot.data()['Equipment Type'],
documentSnapshot.data().Facility,
getFCoord(documentSnapshot.data().Facility, tempFacilities),
documentSnapshot.data()['Priority(1-5)'],
documentSnapshot.data()['Submission Timestamp'],
documentSnapshot.data()['Time to Complete'],
);
tempWorkOrders.push(temp);
});
});
return tempWorkOrders;
}
// final part
console.log('Reached Assigned Schedule');
workOrders().then((y) => {
workers().then((z) => {
assignSchedule(z, y);
for (let i = 0; i < z.length; ++i) {
firestore()
.collection('schedules')
.doc(tempWorkers[i].name)
.set({
schedule: tempWorkers[i].schedule,
})
.then(() => {});
}
});
});
console.log('Reached Assigned Schedule');
function getFCoord(inFacility) {
Facilities().then((x) => {
for (let i = 0; i < x.length; ++i) {
if (inFacility === x[i].name) {
// //console.log(
// // 'fCoord lat: ',
// // x[i].location[0],
// // ', fCoord long: ',
// x[i].location[1],
// );
return [x[i].location[0], x[i].location[1]];
}
}
});
}
// if a task is completed, we remove the work order
// if a task isn't completed by shift end, we subtract the time spent on the task and change the work order to reflect that
// two points (long, lat) distance function
function distBetweenTwoGeoPoints(lat, long, lat2, long2) {
const earthRadius = 6371;
let deltaPhi = ((lat2 - lat) * Math.PI) / 180;
let deltaLambda = ((long2 - long) * Math.PI) / 180;
let phi1 = (lat * Math.PI) / 180;
let phi2 = (lat2 * Math.PI) / 180;
let a =
Math.sin(deltaPhi / 2) ** 2 +
Math.cos(phi1) * Math.cos(phi2) * Math.sin(deltaLambda / 2) ** 2;
let c = 2 * Math.atan(Math.sqrt(a), Math.sqrt(1 - a));
return earthRadius * c;
}
// initial schedule for the day will come from all work orders that haven't been completed before their shift
//based upon technician certification we'd filter the work orders applicable
// letiables for optimization
// probability of failure
// location distance
// priority
// function -> ()
//filter each task by worker which can complete them
//for each worker, filter tasks that they can complete
// urgency score will be function of priority and time since task has been requested
// real time will be time takes to complete + travel time
// multiplier will be a function of how long a task will take and how much time is left in that person's shift
function score(workorder) {
//return workorder.priority * timeSinceRequest(workorder.timeStamp);
return workorder.priority;
}
function listOfTasksPerWorker() {
workOrders().then((Workers) => {
workers().then((workorders) => {
let numWorkers = Workers.length;
let numTasks = workorders.length;
let possibleTasks = [];
for (let i = 0; i < numWorkers; ++i) {
let taskList = [];
for (let j = 0; j < numTasks; ++j) {
//console.log("equipment " + workorders[j].eType);
for (let k = 0; k < workers[i].certifications.length; ++k) {
//console.log("certif " + workers[i].certifications[k]);
if (workorders[j].eType === workers[i].certifications[k]) {
//check certifications
taskList.push(workorders[j]);
}
}
}
possibleTasks.push(taskList);
}
return possibleTasks;
});
});
}
//given task will be apart of taskList
function removeTask(task, taskList) {
let newArr = [];
for (let i = 0; i < taskList.length; ++i) {
if (task.eID === taskList[i].eID) {
newArr = taskList.slice(i, i + 1);
return newArr;
}
}
}
// while workers have shift
// go through workorders
// terminates either when all the workers shifts are full or when there are no work orders
function assignSchedule() {
workOrders().then((Workers) => {
workers().then((workorders) => {
let numDone = 0;
while (numDone < Workers.length && workorders.length > 0) {
console.log('before choose workers');
chooseWorkers(Workers, workorders);
console.log('pass choose workers');
for (let i = 0; i < Workers.length; ++i) {
if (Workers[i].timeLeftinShift <= 0) {
++numDone;
}
}
}
});
});
}
//change time left in workshift
//change location of worker
//say task is assigned, and remove from workorder IF COMPLETED
function assignTask(worker, workorder) {
workOrders().then((workorders) => {
let taskTime =
workorder.timeToComplete +
timeToGetFacility(worker.location, workorder.location);
if (worker.timeLeftinShift < taskTime) {
worker.timeLeftinShift = 0;
workorder.timeToComplete =
worker.timeToComplete - worker.timeLeftinShift;
} else {
worker.timeLeftinShift = worker.timeLeftinShift - taskTime;
workorder.timeToComplete = 0;
workorders = removeTask(workorder, workorders);
}
worker.location = workorder.location;
worker.schedule.push(workorder);
console.log('assign task');
});
}
function chooseWorkers() {
workOrders().then((Workers) => {
workers().then((workorders) => {
for (let i = 0; i < Workers.length; ++i) {
let keep = true;
let bestTaskw1;
let bestTaskw2;
let worker1Tasks = listOfTasksPerWorker(Workers, workorders)[i];
console.log('tasks: ', worker1Tasks);
let schedule = oneSchedule(Workers[i], worker1Tasks);
if (!schedule[0].length) {
break;
} else {
bestTaskw1 = schedule[0][0];
}
console.log('pass schedule');
if (!Workers[i].doneScheduling) {
for (let j = i + 1; j < Workers.length; ++j) {
if (!Workers[j].doneScheduling) {
let worker2Tasks = listOfTasksPerWorker(Workers, workorders)[j];
let schedule2 = oneSchedule(Workers[j], worker2Tasks);
if (!schedule2[0].length) {
break;
} else {
bestTaskw2 = schedule[0][0];
if (bestTaskw1.eID === bestTaskw2.eID) {
let w1SecondSchedule = oneSchedule(
Workers[i],
removeTask(bestTaskw1, worker1Tasks),
);
let w2SecondSchedule = oneSchedule(
Workers[j],
removeTask(bestTaskw1, worker1Tasks),
);
if (
bestTaskw1[1] - w1SecondSchedule[1] <
bestTaskw2[1] - w2SecondSchedule[1]
) {
keep = false;
i = i - 1;
//fix next line
worker1Tasks = removeTask(bestTaskw1, worker1Tasks);
break;
}
}
}
}
}
if (keep) {
assignTask(Workers[i], bestTaskw1, workorders);
}
}
}
});
});
}
function timeToGetFacility(point1, point2) {
const avgSpdKm = 70;
let timeToGetThere =
distBetweenTwoGeoPoints(point1[0], point1[1], point2[0], point2[1]) /
avgSpdKm;
return timeToGetThere;
}
function oneSchedule(worker1, worker1Tasks) {
let time1 = worker1.timeLeftinShift;
let total1 = 0;
let tasks1 = [];
let tempLocation = worker1.location;
while (time1 > 0) {
let bestOrder;
let bestOrderInd;
let bestScorePerHour = 0;
let travelTime = 0;
let bestTravelTime = 0;
console.log('before for');
console.log(worker1Tasks.length.toString());
for (let i = 0; i < worker1Tasks.length; ++i) {
console.log('before if');
console.log('test: ', i, worker1Tasks.length);
if (!worker1Tasks[i].done) {
console.log('after if');
let tempScorePerHour = 0;
console.log('location: ', tempLocation[0], tempLocation[1]);
travelTime = timeToGetFacility(
tempLocation,
worker1Tasks[i].location,
);
console.log('travel time: ', travelTime);
if (time1 - (worker1Tasks[i].timeToComplete + travelTime) < 0) {
tempScorePerHour =
(score(worker1Tasks[i]) *
((time1 - travelTime) / worker1Tasks[i].timeToComplete)) /
time1;
} else {
tempScorePerHour =
score(worker1Tasks[i]) /
(worker1Tasks[i].timeToComplete + travelTime);
}
console.log('score: ', score(worker1Tasks[i]));
console.log('temp: ', tempScorePerHour);
if (tempScorePerHour > bestScorePerHour) {
bestScorePerHour = tempScorePerHour;
bestOrder = worker1Tasks[i];
bestOrderInd = i;
bestTravelTime = travelTime;
}
}
}
if (bestScorePerHour > 0) {
worker1Tasks.splice(bestOrderInd, 1);
//bestOrder.done = true;
tasks1.push(bestOrder);
console.log(bestOrder.eID);
console.log(bestScorePerHour);
if (time1 - (bestOrder.timeToComplete + bestTravelTime) < 0) {
total1 += bestScorePerHour * time1;
time1 = 0;
} else {
total1 += score(bestOrder);
time1 -= bestOrder.timeToComplete + bestTravelTime;
}
console.log(bestOrder.timeToComplete);
tempLocation = bestOrder.location;
} else {
break;
}
}
return [tasks1, total1];
}
}

wait on async fuction +

I want to get the last deviceId.
Please try the following code on a smartphone.
https://www.ofima.ch/file1.html
Inside the function "getConnectedDevices" the variable deviceId ok.
But outside is returned a promise and not the variable deviceId.
How can I get the variable deviceId ?
Thanks
Miche
Explanation:
You need to wrap your alert in an async function and use await. Also to take the value from the promise you needed .then(). Hope the below helps.
Original code:
async function getConnectedDevices() {
var index;
const devices = await navigator.mediaDevices.enumerateDevices();
for (var i=0; i<devices.length; i++) {
if (devices[i].kind == "videoinput") {
index = i;
}
}
var deviceId = devices[index].deviceId;
alert('deviceId is ok: ' + deviceId);
return (deviceId);
}
const deviceId = getConnectedDevices();
alert('deviceId is not defined, why ?: ' + deviceId);
New code:
async function getConnectedDevices() {
let index;
const devices = await navigator.mediaDevices.enumerateDevices();
for (let i=0; i < devices.length; i++) {
console.debug(devices[i]);
if (devices[i].kind == "videoinput") {
index = i;
}
}
console.log('deviceId is ok: ', devices[index]);
return devices[index].deviceId;
}
(async() => {
const deviceId = await getConnectedDevices().then();
alert(`deviceId: ${deviceId}`);
})();
And a quick hack for storing the deviceId in the window
console.log('globalDeviceId should be undefined', window.globalDeviceObj);
async function getConnectedDevices() {
let index;
const devices = await navigator.mediaDevices.enumerateDevices();
for (let i = 0; i < devices.length; i++) {
console.debug(devices[i]);
if (devices[i].kind == "videoinput") {
index = i;
}
}
console.log('deviceId is ok', devices[index]);
return devices[index];
}
function getDeviceId() {
(async() => {
window.globalDeviceObj = await getConnectedDevices().then();
console.log(`globalDeviceId set: ${JSON.stringify(window.globalDeviceObj)}`);
})();
}
function tick() {
if(typeof window.globalDeviceObj === 'undefined'){
requestAnimationFrame(tick);
}else {
alert(`globalDeviceId get: ${JSON.stringify(window.globalDeviceObj)}, with deviceId: ${(window.globalDeviceObj.deviceId)}`)
}
}
function init() {
tick();
getDeviceId();
}
init();

3D force directed graph replacing nodes with images

Ref: 3d Force Directed Graph - Replacing Nodes with Images
How might I add the images to the following excellent code in the same manner as the Stack Overflow answer above?
https://github.com/jexp/neo4j-3d-force-graph/blob/master/particles.html
Assuming that each node may have a property of n.image=/images/imagexxx.jpg how might I apply this image from a local filesystem to its respective node ?
If the property isn't present then render the node as the normal sphere.
Here is my sample code which just renders all nodes as small_image.jpg :
const elem = document.getElementById('3d-graph');
const driver = neo4j.v1.driver("bolt://192.168.1.251", neo4j.v1.auth.basic("neo4j", "test"));
const session = driver.session();
const start = new Date()
session
.run('MATCH (n)-[r]->(m) RETURN { id: id(n), label:head(labels(n)), community:n.name, caption:n.name, size:log(n.links_from+n.links_to)} as source, { id: id(m), label:head(labels(m)), community:m.name, caption:m.name, size:log(m.links_from+m.links_to)} as target, {weight:r.weight, type:type(r), community:case when n.community < m.community then n.community else m.community end} as rel LIMIT $limit', {limit: 5000})
.then(function (result) {
const nodes = {}
const links = result.records.map(r => {
var source = r.get('source');source.id = source.id.toNumber();
nodes[source.id] = source;
var target = r.get('target');target.id = target.id.toNumber();
nodes[target.id] = target;
var rel = r.get('rel'); if (rel.weight) { rel.weight = rel.weight.toNumber(); }
return Object.assign({source:source.id,target:target.id}, rel);
});
session.close();
console.log(links.length+" links loaded in "+(new Date()-start)+" ms.")
const gData = { nodes: Object.values(nodes), links: links}
const Graph = ForceGraph3D()(elem)
.graphData(gData)
.nodeAutoColorBy('community')
.nodeVal('size')
.linkAutoColorBy('community')
.linkWidth(0)
.linkDirectionalParticles('weight')
.linkDirectionalParticleSpeed(0.001)
.nodeLabel(node => `${node.label}: ${node.caption}`)
.onNodeHover(node => elem.style.cursor = node ? 'pointer' : null)
.nodeThreeObject(node => {
var map = new THREE.TextureLoader().load( "small_image.jpg" );
map.minFilter = THREE.LinearFilter;
var material = new THREE.SpriteMaterial( { map: map } );
var sprite = new THREE.Sprite( material );
sprite.scale.set(32,32,1);
return sprite;
});
// Spread nodes a little wider
Graph.d3Force('charge').strength(-150);
})
.catch(function (error) {
console.log(error);
});
const elem = document.getElementById('3d-graph');
const driver = neo4j.v1.driver("bolt://localhost", neo4j.v1.auth.basic("neo4j", "test"));
const session = driver.session();
const start = new Date()
session
.run('MATCH (n:Entity)-[r]->(m:Entity) WHERE n.name="new york" RETURN { id: id(n), label:head(labels(n)), community:n.name, caption:n.name, image:n.image, size:log(n.links_from+n.links_to)} as source, { id: id(m), label:head(labels(m)), community:m.name, caption:m.name, image:m.image, size:log(m.links_from+m.links_to)} as target, {weight:r.weight, type:type(r), community:case when n.community < m.community then n.community else m.community end, image:case when n.image < m.image then n.image else m.image end} as rel LIMIT $limit', {limit: 5000})
.then(function (result) {
const nodes = {}
const links = result.records.map(r => {
var source = r.get('source');source.id = source.id.toNumber();
nodes[source.id] = source;
var target = r.get('target');target.id = target.id.toNumber();
nodes[target.id] = target;
var rel = r.get('rel'); if (rel.weight) { rel.weight = rel.weight.toNumber(); }
return Object.assign({source:source.id,target:target.id}, rel);
});
session.close();
console.log(links.length+" links loaded in "+(new Date()-start)+" ms.")
const gData = { nodes: Object.values(nodes), links: links}
const Graph = ForceGraph3D()(elem)
.graphData(gData)
.nodeAutoColorBy('community')
.nodeVal('size')
.linkAutoColorBy('community')
.linkWidth(0)
.linkDirectionalParticles('weight')
.linkDirectionalParticleSpeed(0.001)
.nodeLabel(node => `${node.label}: ${node.caption}`)
.onNodeHover(node => elem.style.cursor = node ? 'pointer' : null)
.nodeThreeObject(node => {
var map = new THREE.TextureLoader().load((node.image != null ? node.image : ""));
map.minFilter = THREE.LinearFilter;
var material = new THREE.SpriteMaterial( { map: map } );
var sprite = new THREE.Sprite( material );
sprite.scale.set(32,32,1);
if (node.image){
return sprite; }
else return false;
});
// Spread nodes a little wider
Graph.d3Force('charge').strength(-150);
})
.catch(function (error) {
console.log(error);
});

Multi document creation in sub-collection in Firestore

I am trying to write a function that will:
Create documents in a sub collection
Allow for a then/catch call back after all sub documents have been created
export const doCreateSubs = (Id, count) => {
if (count > 0 && count <= 50){
const times = n => f => {
let iter = i => {
if (i === n) return;
f(i);
iter(i + 1);
};
return iter(0);
};
times(count)(i => {
db
.collection("parent")
.doc(`${Id}`)
.collection("sub")
.add({
subName: `name ${i + 1}`,
dateCreated: new Date()
});
});
}
}
I've played around with batch but it doesn't work with .collection. I know my function is really poor - is there a generally bettery way of doing this?
So i've just realised you can .doc() with no value and it will create a uid for the key. I can also return .commit and recieve a call back when it's complete!
export const doCreateSubs = (Id, count) => {
if (count > 0 && count <= 50){
const times = n => f => {
let iter = i => {
if (i === n) return;
f(i);
iter(i + 1);
};
return iter(0);
};
const batch = db.batch();
times(count)(i => {
const ref = db
.collection("parent")
.doc(`${Id}`)
.collection("subs")
.doc();
batch.set(ref, {
boxName: `Sub ${i + 1}`,
dateCreated: new Date()
});
});
return batch.commit();
}
}

When to use ReactiveDict vs ReactiveVar

I'm in Meteor and have been using Reactive Var in my project with no issues. In this current example I'm not sure if I need to use a ReactiveDict instead because I'm getting no reactivity with ReactiveVar.
I'm setting the value of the reactiveVar to a mongo query that is resulting in an array of objects.
Template.MasterList.onCreated(function () {
this.teacherList = new ReactiveVar('');
});
Template.MasterList.onRendered(function () {
var weekNum = Session.get('CurrentWeek').substr(0, 1);
var week = 'Week' + weekNum;
var query1 = {};
query1[week] = { $in: ['JC', 'JF', 'F']};
this.teacherList.set(Programs.find({ $and: [{ CampYear: Session.get('GlobalCurrentCampYear') }, query1]}, { sort: { FullName: 1 }}).fetch());
});
One object in the array would look like:
{ ...
Students: {
Week1: {
Monday: ['Joe', 'Mary']
},
Week2: {},
Week3: {}
}
...
}
One of the objects in the array may change to something like:
{ ...
Students: {
Week1: {
Monday: ['Joe', 'Mary', 'Bill']
},
Week2: {},
Week3: {}
}
...
}
When a change to one of the objects happens, the reactiveVar doesn't see the change in the array to re-fire the helper. Is a ReactiveDict to be used here instead?
EDIT:
Helper function:
saturdayTeacher: function (name) {
var weekNum = Session.get('CurrentWeek').substr(0, 1);
var week = 'Week' + weekNum;
var teachers = Template.instance().teacherList.get();
for (var i = 0, len = teachers.length; i < len; i++) {
if (_.contains(teachers[i].Students[week].Saturday, name)) {
Meteor.defer(function () {
i = 0;
});
var teacher = teachers[i].FullName.split(' ');
return teacher[0] + " " + teacher[1].slice(0, 1);
}
}
},
What will help you in a very easy way, is to add an autorun to your onRendered-Function, where you set your ReactiveVar. Because the onRendered-Function is only executed once. When I get it right, you want to listen on changes in the cursor, Session.get('CurrentWeek') and Session.get('GlobalCurrentCampYear').
So try this:
Template.MasterList.onRendered(function () {
var self = this;
this.autorun(function() {
var weekNum = Session.get('CurrentWeek').substr(0, 1);
var week = 'Week' + weekNum;
var query1 = {};
query1[week] = { $in: ['JC', 'JF', 'F']};
self.teacherList.set(Programs.find({ $and: [{ CampYear: Session.get('GlobalCurrentCampYear') }, query1]}, { sort: { FullName: 1 }}).fetch());
});
});
Than it will be executed all the time the result of the query or the Session-Values change.

Resources