Firebase - How to update many children and not delete others in AngularFire - angularjs

I want to use update() on firebase ref to update many children in one operation.
To do this I passed the object with values to change.
Here is the output of console.log(angular.toJson(change,1))
{
"10": {
"otherRubies": 30
},
"11": {
"otherRubies": 30
}
}
At the beginning i have:
Then i do:
var refUsers = new Firebase(FBURL).child('users/');
refUsers.update(change);
So i want to have:
but instead of that i get:
Is there any way to do that ?

Update is not a recursive operation. So it's calling set on the child paths. If you call update at users/, you're saying don't delete any keys under user/ which are not in my data, when you want to say, don't delete any keys in the child records of user/.
Instead, iterate the records and call update on each:
var refUsers = new Firebase(FBURL).child('users/');
for(key in change) {
if( change.hasOwnProperty(key) ) {
refUsers.child(key).update( change[key] );
}
}

With Firebase 3 you can do the update by writing :
update = {};
update['10/otherRubies'] = 30;
update['11/otherRubies'] = 30;
refUsers.update(change);
This way of updating the data is not in the documentation but it worked for me.

This is a sample of recursive update:
function updateRecursively(path, value) {
for (let key in value) {
if (value[key] instanceof Object) {
updateRecursively(`${path}/${key}`, value[key]);
} else {
firebase.database().ref(`${path}/${key}`).set(value[key]);
}
}
}
Usage:
updateRecursively('users', {
"10": {
"otherRubies": 30
},
"11": {
"otherRubies": 30
}
})

Related

Generating non duplicate items in componentDidMount using Redux

I am creating a multipage application. When the user navigates to one of my pages componentDidMount triggers and currently generates 4 random numbers within a range I have specified and sends them through my reducer. This eventually comes back in the form of an array.
Within componentDidMount I have a loop to call my generateRandomNumber function four times. However, if I go to log the output array I get a blank array, which is the initial state for said reducer.
Logging the array in componentDidUpdate, or anywhere after the mount returns what I want it to but that doesn't help me in checking for duplicates as I cannot check for duplicates if I am checking against a blank array. Everything should be without delay, but there seems to be an issue with trying to read from this.props.currentUserList from within componentDidMount.
I need to verify that I am not adding two of the same user into my array, but I need the pre-check to all be done by the time this appears on-screen.
//gives me a random user from my array
generateRandomUser() {
return myArray[Math.floor(Math.random() * 100) + 1]
}
//sends 4 randomUsers through my actions to my reducers
generateNewID() {
let amountOfOptions = 4;
while (amountOfOptions > 0) {
let randomUser = this.generateRandomUser();
if (this.props.currentUserList.length === 0) {
this.props.setCurrentUser(randomUser);
} else {
//this never fires as currentUserList is somehow still == []
this.checkForDuplicates();
}
amountOfOptions--;
}
}
componentDidMount() {
this.generateNewID()
console.log(this.props.currentUserList)
//returns []
}
componentDidUpdate() {
console.log(this.props.currentUserList)
// returns [
// user2: {
// name: 'name'
// },
// user4: {
// name: 'name'
// },
// user28: {
// name: 'name'
// },
// user92: {
// name: 'name'
// },
// ]
}
I am not sure about the implementation of the array. However if the required output is to get 4 random users then instead of of calling setcurrentuser 4 times, you can generate 4 users and then set them at once.
generateNewID() {
let amountOfOptions = 4;
let randomUserList = [];
while (amountOfOptions > 0) {
let randomUser = this.generateRandomUser();
if (randomUserList.length === 0) {
randomUserList.push(randomUser);
} else {
//this never fires as currentUserList is somehow still == []
this.checkForDuplicates();
}
amountOfOptions--;
}
this.setCurrentUser(randomUserList);
}

How to update array value with same key in session storage

I have two tabs in my admin interface. I am storing the response in my session storage. When I do the updation of any records in the tab or if I insert new record also, the same thing should be reflected in the storage also. But currently, the changes are not getting reflected in the storage. I tried my best to sort out, but I could not able to succeed. Any help/advice greatly appreciated.
Angularjs:
$scope.Pool = [];
if (!localStorageService.get('Pool')) {
Role.getPool().success(function(data) {
if (data.responseCode === 0) {
_.forEach(data.response.demoPool, function(value, key) {
dataObj = {};
dataObj.id = value.poolId;
dataObj.value = value.poolName;
$scope.Pool.push(dataObj);
});
localStorageService.set('Pool', $scope.Pool);
} else {
$scope.alerts.alert = true;
$scope.alerts.type = 'danger';
$scope.alerts.msg = data.errorMsg;
}
})
First time it will do because !localStorageService.get('Pool') becomes true. But next time it will return false because storage has value already, it will not get inside the if condition. so to resolve this remove the session storage 'Pool' to allow to execute your Role.getPool().success(function(data) {
if (!sessionStorage.length) {
// Ask other tabs for session storage
localStorage.setItem('getSessionStorage', Date.now());
};
window.addEventListener('storage', function (event) {
switch (event.key) {
case 'getSessionStorage':
// Some tab asked for the sessionStorage -> send it
localStorage.setItem('sessionStorage', JSON.stringify(sessionStorage));
localStorage.removeItem('sessionStorage');
break;
case 'sessionStorage':
// sessionStorage is empty -> fill it
var data = JSON.parse(event.newValue);
for (key in data) {
sessionStorage.setItem(key, data[key]);
}
break;
}
});

Most efficient way to check if any element in a JSON array contains a specific id?

I am using Node v8.1.3
I have a JSON array as following:
[
{
"id":99,
"name": "ABC"
},
{
"id": 187,
"name": "AXZ"
}
]
This array has around 213000 e=objects in it.
Also, the ids in the objects are not in any order or pattern.
Now, I want to find if a particular id matches any ID in the array? what is the fastest wait to do it?
I tried
isIdValid(id) {
console.log(id)
return this.list.filter((elem) => {
return elem.id == id
}).length > 0;
}
But this is taking over 4 seconds.
One option is to first sort the whole list (or insert it into a binary search tree) which takes some time but is only done once. and from there you can use binary search for the ID which is way faster.
here is a sample bst code for node:
js-bst
also here is a package that can be used to query json data list very faster: Defiant
Edit
actually creating a hash table is a faster solution than a bst; here is a sample code that does the job:
data = [
{
"id":99,
"name": "ABC"
},
{
"id": 187,
"name": "AXZ"
}
]
var hashCache = {};
data.forEach(function(item){
hashCache[item.id] = item.name
});
// Usage:
var id = '99';
var record = hashCache[id];
if (record) {
alert(record);
} else {
console.log('no match found');
}
you should also consider that this hash table only works if the IDs are unique. otherwise, you need to store a list of names in the hash table for each ID.
These are not the "Most efficient way to check". I'm posting here just as a reference about some ways to prepare the data to have a more performant search by a specific key.
Also is worth considering that in this script, Map can have a better performance, just because it is the last of all the executions. When its turn comes, V8 would have already been done some optimizations internally. So try to run each of them separately to have better findings.
'use strict';
////////////////////////
// GENERATE TEST DATA //
////////////////////////
const dataSet = [];
let count = 213000;
while(count--) dataSet.push({id: count});
let idToBeFound = 212999;
// //////////////////////////
// // Using Literal Object //
// //////////////////////////
console.time('creatingIndexAsLiteralObject');
const literalObjectKeyedByID = dataSet.map(item => ({[item.id]: true}));
console.timeEnd('creatingIndexAsLiteralObject');
console.time('isIdValidSeekingOnLiteralObject');
console.log('isIdValidSeekingOnLiteralObject :: Found?', isIdValidSeekingOnLiteralObject(idToBeFound, literalObjectKeyedByID));
console.timeEnd('isIdValidSeekingOnLiteralObject');
function isIdValidSeekingOnLiteralObject(id, list) {
return !!list[id];
}
// //////////////////////
// // Using Set Object //
// //////////////////////
console.time('creatingIndexAsSetObject');
const setObject = new Set(dataSet.map(item => item.id));
console.timeEnd('creatingIndexAsSetObject');
console.time('isIdValidSeekingOnSet');
console.log('isIdValidSeekingOnSet :: Found?', isIdValidSeekingOnSet(idToBeFound, setObject));
console.timeEnd('isIdValidSeekingOnSet');
function isIdValidSeekingOnSet(id, list) {
return list.has(id);
}
//////////////////////
// Using Map Object //
//////////////////////
console.time('creatingIndexAsMapObject');
const mapObjectKeyedByID = new Map();
dataSet.forEach(item => mapObjectKeyedByID.set(item.id));
console.timeEnd('creatingIndexAsMapObject');
console.time('isIdValidSeekingOnMap');
console.log('isIdValidSeekingOnMap :: Found?', isIdValidSeekingOnMap(idToBeFound, mapObjectKeyedByID));
console.timeEnd('isIdValidSeekingOnMap');
function isIdValidSeekingOnMap(id, list) {
return list.has(id);
}

How to avoid duplicates to local storage in Angular.js

I use Angular.js localstorage to store the values in local
Here is plnkr Demo
everything works fine but how to avoid inserting a product or a value twice? (how to avoid duplicates) while pushing a value to local
You just push items to an array without any further checks in cloneItem(). You can update its implementation to first check for duplicate (just a quick idea):
$scope.cloneItem = function (todo) {
// Check for duplicate on id
if($scope.$storage.notes.filter(function (note) {
return note.id === todo.id;
}).length > 0) {
return;
};
// Insert if not duplicate
$scope.$storage.notes.push({
"price": todo.price,
"id": todo.id,
"quan": todo.quan
});
}
I think you can use a shorter way than the Nicolas one:
$scope.cloneItem = function (todo) {
if ($scope.$storage.notes.indexOf(todo) == -1) {
//if the object is not in the array
$scope.$storage.notes.push({
"price": todo.price,
"id": todo.id,
"quan": todo.quan
});
}
//else you just do nothing
}

Node.js : control flow with forEach

I am trying to create array from database objects :
I have entity "group" wich hasMany "devices", I want to create array whit all groups and for each groups the list of his devices :
[
{
"group_id": “1”,
"name": “My_group”,
"devices_list": [1, 2, 18]
},
{
"group_id": “2”,
"name": “My_second_group”,
"devices_list": [3, 24]
}
]
I tried several ways like this :
Group.all(function (err, groups) {
var resJson = {};
groups.forEach(function(group, index){
group.devices(function(err, devices){
resJson[index] = group;
console.log(devices);
resJson[index].devices_list = devices;
//End of the loop
if (index == groups.length -1){
send({code: 200, data: resJson});
}
});
});
});
EDIT 1 :
I tried this way too :
var resJson = {};
groups.forEach(function(group, index){
group.devices(function(err, devices){
resJson[index] = group;
resJson[index].devices_list = [];
devices.forEach(function(device,index2){
resJson[index].devices_list.push(device);
});
//End of the loop
if (index == groups.length -1){
send({code: 200, data: resJson});
}
});
});
But finally, my resJson contains only empty groups (groups without device associated), the other groups are not visible. Thus my devices_list are all empty whereas the console.log(devices) display devices.
It seems that the "send" instruction is processed before the treatment of non-empty groups.
What is the rigth way to do this ?
Thank you for your time
Instead of tracking and using an index against the length of the list perhaps you could use an after type of construct. I really enjoy them and they're easy to integrate and serve the perfect purpose for doing something after a set number of times.
First, lets define an after function you can use.
var after = function(amount, fn) {
var count = 0;
return function() {
count += 1;
if (count >= amount) {
fn.apply(arguments);
}
};
};
That should work for you now, let's modify your code sample to use this.
var json = []; // To return, you originally wanted an array.
Group.all(function(err, groups) {
if (err) {
// Handle the error
} else {
var sendJson = after(groups.length, function(json) {
send({code: 200, data: json});
});
groups.forEach(function(group) {
group.devices(function(err, devices) {
if (err) {
// Handle the error...
} else {
group.devices_list = devices;
json.push(group); // This part is different, using this method you'll match the JSON you gave as your "goal"
}
// This is outside the if/else because it needs to be called for every group
// regardless of change. If you do not call this the exact number of times
// that you specified it will never fire.
sendJson(json);
});
}
});
Perhaps something like that might clear up your issue.

Resources