How to access node in the firebase databse - javascript

My aim is to have each user select a total of 6 players. when each player is selected, the player id is sent to a node on the database called 'total'using the push () method. The code is written below
var ref = firebase.database().ref().child('players');
var ref3 = firebase.database().ref().child('users').child(uid).child('total');
$scope.players = $firebaseArray(ref);
console.log ($scope.players);
$scope.history = [];
$scope.buy = function(player) {
//remove if already added locally
var index = $scope.history.indexOf(player);
if(index>=0){
$scope.history.splice(index,1);
return;
}
//remove if already added on firebase
//max 6 allowed
if($scope.history.length>=6){
alert('max 6 allowed');
return;
}
var selected = $scope.history.reduce(function(a,b){
a[b.position] = (a[b.position] || 0) + 1;
return a;
}, {}) || {};
if(!selected[player.position] || selected[player.position]<2){
$scope.history.push(player);
ref3.push(player.id);
}else{
alert('You can add only two players per position');
}
};
$scope.getTotal = function(){
return $scope.history.reduce(function(tot, p){
tot = tot - p.price;
return tot;
}, $scope.total);
};
this is how the database is structured :
{
"players" : [ {
"R" : 0,
"Team" : "Industry",
"Y" : 0,
"assists" : 0,
"goals" : 0,
"id" : 1,
"name" : "Yasin 'YB' Amusan",
"position" : "forward",
"price" : 8000000
}, {
"R" : 0,
"Team" : "Industry",
"Y" : 0,
"assists" : 0,
"goals" : 0,
"id" : 2,
"name" : "Hassan 'Hasi' Akinyera",
"position" : "defender",
"price" : 5000000
}],
"users" : {
"l3J1TVsFNLMi0Oxg6hz4AJpacE53" : {
"email" : "awoniyideji#yahoo.com",
"fullname" : "Djflex11",
"teamname" : "deji awoniyi",
"total" : {
"-Kpl19z_25IEhiCEFrui" : 1,
"-Kpl1ARqT-v_btJ7OAq2" : 2,
"-Kpl1AsdodYWVPWWd5xA" : 2,
"-Kpl1iN7a7PLU-tnkKc4" : 1,
"-Kpl1j5CtN6c_mnmWLP-" : 1,
"-Kpl1k0BNCP5NNFV5uX6" : 1
},
"userName" : "awoniyideji#yahoo.com",
"week" : "no",
}
}
}
My ISSUE
The aim is that a player cannot be selected twice by the same user. MY code currently prevents a player from being selected twice locally, but the same player id can be pushed to the firebase database. My issue is how to basically check the total node so that the selected player if already "pushed" into database, will be removed instead of inserted into the database. I know that 'indexOf' is to be avoided with firebase.

This should work:
if(ref3.toJSON().hasOwnProperty(playerId)){
ref3.child(playerId).remove();
}
References:
Check for key in JSON
Remove from DB

Related

Find total amount for each agent from nested nodes in Firebase Database

I am learning on the Job and I would like to display total amount an agent has sold. This is a nested object as the json below indicates.
Thanks in advance
"68600" : {
"name" : "Pablo picasso",
"sales" : {
"-MVFp1JDHikxD1d-6q2w" : {
"amount" : 650,
"id" : "-MVFp1JDHikxD1d-6q2w",
"timestamp" : 1615190041147
},
"-MVFp505IskBRrooof-Z" : {
"amount" : 840,
"id" : "-MVFp505IskBRrooof-Z",
"timestamp" : 1615190056307
},
"-MVFpE2Q93tbDgQmVFQE" : {
"amount" : 650,
"id" : "-MVFpE2Q93tbDgQmVFQE",
"timestamp" : 1615190093320
},
"-MVFqRncyoTuk26MvhJU" : {
"amount" : 1700,
"id" : "-MVFqRncyoTuk26MvhJU",
"timestamp" : 1615190411796
}
}
},
"786500" : {
"sales" : {
"-MVQIKvKzr_BRCbP2nlv" : {
"amount" : 655,
"id" : "-MVQIKvKzr_BRCbP2nlv",
"timestamp" : 1615365757283
}
}
},
Below is my implementation, when i console.log it is displaying the wrong tally.
firebase.initializeApp(firebaseConfig);
const db = firebase.database();
db.ref('sellers').on('value', snapshot => {
const val = snapshot.val();
let idx = 0;
for (let key in val)
{
const agentSales = val[key]['sales'];
for (let salesObj in agentSales)
{
_sales = agentSales[salesObj].amount;
total = total + _sales;
// console.log(_sales);
// for(let total in _sales){
// console.log(_sales[total].amount);
// }
}
//if(snapshot.hasChildren())
//{
// var total = 0;
// snapshot.forEach(function(item){
// total += item.child('amount').val();
// });
// console.log(total);
//}
}
});

Calculus with objects in javascript

I have an object that contains 2 fields: day_active and day_inactive. (the object is in the javascript snippet below)
And what I want to obtain is another object that is based on this formula:
count(day_active (on date x))-count(day_inactive (on date x)
{
{
"date" : "2019-09-19",
"type" : "groupC",
"count" : 2.0 // (5.0 - 3.0) - how many groupC were on day_active(2019-09-19) minus how many groupC were on day_inactive(2019-09-19)
},
{
"date" : "2019-09-19",
"type" : "groupW",
"count" : -2.0 // (3.0 - 5.0)
},
{
"date" : "2019-09-11",
"type" : "groupW",
"count" : -2.0 // (8.0 - 10.0)
},
{
"date" : "2019-10-08",
"type" : "groupW",
"count" : 7.0 // (7.0 - 0.0)
}
}
I tried this code but is not taking all the cases and the result is incomplete:
let items = {
"day_inactive" : [
{
"date" : "2019-09-19",
"type" : "groupC",
"count" : 3.0
},
{
"date" : "2019-09-11",
"type" : "groupW",
"count" : 10.0
},
{
"date" : "2019-09-19",
"type" : "groupW",
"count" : 5.0
},
{
"date" : "2019-10-07",
"type" : "groupW",
"count" : 9.0
},
{
"date" : "2019-10-05",
"type" : "groupW",
"count" : 3.0
},
],
"day_active" : [
{
"date" : "2019-09-11",
"type" : "groupW",
"count" : 8.0
},
{
"date" : "2019-09-19",
"type" : "groupW",
"count" : 3.0
},
{
"date" : "2019-10-08",
"type" : "groupW",
"count" : 7.0
},
{
"date" : "2019-09-19",
"type" : "groupC",
"count" : 5.0
}
]
}
let auxObj = {}
for (let i = 0; i < items.day_active.length; i++) {
for (let j = 0; j < items.day_inactive.length; j++) {
if (items.day_active[i].date == items.day_inactive[j].date && items.day_active[i].type == items.day_inactive[j].type) {
// console.log("yes")
auxObj.date = items.day_active[i].date
auxObj.type = items.day_active[i].type
auxObj.count = items.day_active[i].count - items.day_inactive[j].count
}
}
}
console.log(auxObj)
How can I solve this in a simple way? Thank you for your time!
Follow along the comments for explanation...
// let's create an empty object
let output = {};
// and start copying active days...
for (const obj of items.day_active) {
// the following `key` is just for grouping purposes...
const key = `${obj.date}-${obj.type}`;
output[key] = { ...obj };
}
// Now let's look at inactive days...
for (const obj of items.day_inactive) {
// the following `key` is just for grouping purposes...
const key = `${obj.date}-${obj.type}`;
// is this the first time we're looking at this `date-type`? let's add it with 0 count
if (!output[key]) {
output[key] = { ...obj, count: 0 };
}
// and subtract it from active days count
output[key].count -= obj.count;
}
// let's remove the `key` we created earlier...
output = Object.values(output);
// here's the output
console.log(output);
From the sample input given, this is the result we get:
[ { date: '2019-10-11', type: 'groupW', count: -2 },
{ date: '2019-10-19', type: 'groupW', count: 3 },
{ date: '2019-10-08', type: 'groupW', count: 7 },
{ date: '2019-10-19', type: 'groupC', count: 5 },
{ date: '2019-09-19', type: 'groupC', count: -3 },
{ date: '2019-09-19', type: 'groupW', count: -5 },
{ date: '2019-10-07', type: 'groupW', count: -9 },
{ date: '2019-10-05', type: 'groupW', count: -3 } ]
I think this one will be more efficient, i named the object after me cause...idn
let marios = {};
items.day_active.forEach(d => marios[d.date+'_'+d.type] = d.count || 0);
items.day_inactive.forEach(d => marios[d.date+'_'+d.type] = marios[d.date+'_'+d.type] ? marios[d.date+'_'+d.type] - (d.count || 0) : (d.count || 0));
console.log(marios);
The logic behind it is that we create an object and we create a property for each date present in the data sets, starting with the first terms of the formla, ending with the subtraction of the second part, and by defaulting to 0 for each appropriate case.
In the end you can iterate the properties of the object, split the string on '_' to read each propertie's date and group and create an array of the results ( if you have trouble with this let me know )

Firebase functions getChild value

I am having a problem on firebase functions. What I trying to do is when Items's child gets updated, then I want to get the value of Count and do further calculation, But what I am facing is that the firebase log console always shows an erreor "TypeError: Cannot read property 'val' of undefined".
JSON structure
"VTEST" : {
"A" : {
"Count" : 5,
"Items" : {
"item1" : "apple"
},
"NUMBER" : 5
},
"B" : {
"Count" : 8,
"Items" : {
"item1" : "orange;"
},
"NUMBER" : 3
},
"C" : {
"Count" : 10,
"Items" : {
"item1" : "grape"
},
"NUMBER" : 7
},
"D" : {
"Count" : 12,
"Items" : {
"item1" : "grava"
},
"NUMBER" : 10
},
"E" : {
"Count" : 15,
"Items" : {
"item1" : "fish"
},
"NUMBER" : 12
},
"F" : {
"Count" : 18,
"Items" : {
"item1" : "chicken;"
},
"NUMBER" : 8
}
}
My code:
exports.ItemCount = functions.database.ref('/VTEST/{ID}/Items').onUpdate((updateRef, context) => {
var childCount = updateRef.after.numChildren();
var newReference = updateRef.after.ref.parent.child('/Count');
var Count = newReference.val();
Count = Count + childCount;
return updateRef.ref.update({Count})
})
What I expect is the Count's value will be update, but it always show error : "TypeError: Cannot read property 'val' of undefined"
Can anyone tell me what am I doing wrong here, I don't get it.
The problem comes from the fact that a Reference does not have a val() method. You need to use the once() method to get the value of the corresponding database location.
The following adapted code should work:
exports.ItemCount = functions.database
.ref('/VTEST/{ID}/Items')
.onUpdate((updateRef, context) => {
var childCount = updateRef.after.numChildren();
var newReference = updateRef.after.ref.parent.child('/Count');
return newReference.once('value').then(dataSnapshot => {
var Count = dataSnapshot.val();
Count = Count + childCount;
return newReference.parent.update({ Count: Count });
});
});
However, depending on your exact requirements, you may decide to use a Transaction, see https://firebase.google.com/docs/database/web/read-and-write#save_data_as_transactions

Can I make Mongo map reduce count multiple values of an object?

I have a collection that I am trying to map reduce by id and date to produce a graph for sales of a product in store vs online. A new object is created for each transaction, so I would like to reduce them to a total count for a given day. An object looks something like this:
object
{
"ProductID": 1
"Purchase Method": In Store
"Date": 2018-01-16
"Count": 5
}
What I am trying to achieve as output is to have in store and online purchases combined into 1 object with a key being the id and the date and then the value being the counts of each method as shown below:
ProductID: 1
Date: 2018-01-16
[
{Name: "In store", Count: 3}
{Name: "Online", Count: 2}
]
My current method was to map the objects by Id, date, and Purchase Method so the reduce would get the total count for that id on that date using that method, but this leads to having two entries for an id and date, 1 for in store and 1 for online. This is the current state of my functions:
var mapDailySales = function() {
var sale = this;
/*Converts timestamp to just date */
var pad = function pad(n, width, z) {
z = z || '0';
n = n + '';
return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
};
var d = sale.Date;
var date = d.getFullYear() + "-" + pad(d.getMonth() + 1, 2, 0) + "-" + pad(d.getDate(), 2, 0);
emit({ProductId: sale.ProductID, Date:date, Method: sale.PurchaseMethod},
{Name: sale.PurchaseMethod, Count: 1})
};
var reduceDailySales = function(key, value) {
var res = {Name: 0, Count: 0};
value.forEach(function(value){
res.Name = value.Name;
res.Count += value.Count;
});
return res;
};
Current Output looks something like this:
{
"_id" : {
"ProductId" : 1,
"Date" : "2018-01-16",
"Method" : "Online"
},
"value" : {
"Name" : "Online",
"Count" : 3
}
}
Is there a way to achieve my desired output without map reducing again on the current output?
You can use aggregation pipeline to get the results instead of mapReduce, $group by ProductID and Date, with $project you can map counts to an array
added $out to write the results to new collection, removing it will return a cursor
db.prod.aggregate([
{$group : {
_id : {ProductID : "$ProductID", Date : "$Date"},
onlineCount : {$sum : {$cond : [{$eq : ["$PurchaseMethod", "Online"]}, "$Count" , 0]}},
storeCount : {$sum : {$cond : [{$eq : ["$PurchaseMethod", "In Store"]}, "$Count" , 0]}}
}
},
{$project : {
_id : 0,
ProductID : "$_id.ProductID",
Date : "$_id.Date",
counts : [{Name: "In Store", Count: "$storeCount"},{Name : "Online", Count: "$onlineCount"}]
}},
{$out : "count_stats"}
]).pretty()
collection
> db.prod.find()
{ "_id" : ObjectId("5a98ce4a62f54862fc7cd1f5"), "ProductID" : 1, "PurchaseMethod" : "In Store", "Date" : "2018-01-16", "Count" : 5 }
{ "_id" : ObjectId("5a98ce4a62f54862fc7cd1f6"), "ProductID" : 1, "PurchaseMethod" : "Online", "Date" : "2018-01-16", "Count" : 2 }
>
result
> db.count_stats.find()
{ "_id" : ObjectId("5a98d3366a5f43b12a39b4ac"), "ProductID" : 1, "Date" : "2018-01-16", "counts" : [ { "Name" : "In Store", "Count" : 5 }, { "Name" : "Online", "Count" : 2 } ] }
>
if you want to use mapReduce, you can use finalize to reduce or transform the result further
db.prod.mapReduce(
<map>,
<reduce>,
{
out: <collection>,
finalize: <function>
}
)

Compare Multiple JSON Arrays

I have 3 arrays as displayed below. I have no control over the arrays.
groups_array = [ {
"group" : "Mobile Test Region",
"id" : "251"
}, {
"group" : "Mobile Demo Region",
"id" : "252"
} ]
locations_array = [ {
"location" : "M Testing",
"id" : "1376"
}, {
"location" : "Trade Show Machine",
"id" : "1403"
}, {
"location" : "M Trailer",
"id" : "1471"
}, {
"location" : "Test Los Angeles",
"id" : "1475"
} ]
pairs_array = [ {
"location_id" : "1376",
"group_id" : "251"
}, {
"location_id" : "1475",
"group_id" : "251"
}, {
"location_id" : "1403",
"group_id" : "252"
}, {
"location_id" : "1471",
"group_id" : "252"
} ]
Here is the code I used to loop through the pairs_array and retrieve the location_id's that correspond with the group id. Ti.API.info(pairs_array[s].location_id); outputs 2 location ID's based on the groupid given using e.rowData.groupid.
for (var s = 0; s < pairs_array.length; s++) {
if (e.rowData.groupid === pairs_array[s].group_id) {
Ti.API.info(pairs_array[s].location_id);
}
}
I am trying to compare the strings and retrieve the location names using the location_id's ive gotten from the IF statement. Should I just push the results into an array and loop through the location_array and the results and compare? If so, I'd like to see a good code snippet for that since the few times I tried I was not getting the expected output.
for (var s = 0; s < pairs_array.length; s++) {
if (e.rowData.groupid === pairs_array[s].group_id) {
Ti.API.info(pairs_array[s].location_id);
// find location name
for(var t = 0; t < locations_array.length; t++)
{
if(locations_array[t].id == pairs_array[s].location_id)
{
location_name = locations_array[t].location;
}
}
}
}

Categories