firebase - handle no data from snapshot - javascript

I have a firebase reference, where I pull data down for a specific custom index I created.
requestsRef
.orderByChild('systemgameindex')
.startAt(lastrequest.systemgameindex.toString())
.endAt(lastrequest.systemgameindex.toString() + '~')
.limitToFirst(customElem.dataops.limit + 1)
.on('child_added', function (snapshot) {
var request = snapshot.val() || {};
request.key = snapshot.key();
request.systemColor = customElem.getSystemColor(request.system);
request.description = customElem.truncateText(request.description, 65);
customElem.getUserProfile(request);
customElem.getCommentCount(request.key);
if (request.systemgameindex !== lastrequest.systemgameindex) { customElem.push('requests', request); };
customElem.removeSpinnerRoo();
});
Right before I make the call to firebase, I have a custom spinner I dislay with a function called addSpinnerRoo(), and when data is returned, I make a call to removeSpinnerRoo() to hide the spinner on the DOM.
It works beautifully when there's data to return from firebase, but if the firebase query brings back no results, the callback on child_added never gets fired, so I have a spinner still spinning on the DOM.
Is there a way to handle when there's no data returned within Firebase?
Any insight would be appreciated a lot. Thanks

After reading this from the documentation from here:
The callback function receives a DataSnapshot, which is a snapshot of the data. A snapshot is a picture of the data at a particular database reference at a single point in time. Calling val() on a snapshot returns the JavaScript object representation of the data. If no data exists at the reference's location, the snapshots value will be null.
I was able to do use "val" instead of "child_added" to actually have firebase still fire the callback for the ".on()" method. So my code now looks like this:
var data = snapshot.val();
if (data !== null && data !== undefined) {
var requests = _.map(data, function (val, key) {
val.key = key;
return val;
});
_.each(requests, function (request) {
request.systemColor = customElem.getSystemColor(request.system);
request.description = customElem.truncateText(request.description, 65);
customElem.getUserProfile(request);
customElem.getCommentCount(request.key);
customElem.push('requests', request);
});
}
customElem.removeSpinnerRoo();
And with that, I was able to get what I needed. If this helps anyone, great...

Related

Firebase real time database access data array from deleted node

I am deleting a FRTDB node, I want to access deleted data from that node. the functions looks as follow:
exports.events = functions.database.ref('/events/{eventId}').onWrite(async (change, context) => {
const eventId = context.params.eventId
if (!change.after.exists() && change.before.exists()) {
//data removed
return Promise.all([admin.database().ref(`/events/${eventId}/dayofweek`).once('value')]).then(n => {
const pms = []
const days = n[0]
days.forEach(x => {
pms.push(admin.database().ref(`${change.before.val().active ? 'active' : 'inactive'}/${x.key}/${eventId}`).set(null))
})
return Promise.all(pms)
});
else {
return null;
}
})
The probem I am having is that
admin.database().ref(`/events/${eventId}/dayofweek
do not loop the data because it seems data is no longer there so the forEach is not working. How can I get access to this data and get to loop the deleted data?
Of course you won't be able to read data that was just deleted. The function runs after the delete is complete. If you want to get the data that was just deleted, you're supposed to use change.before as described in the documentation:
The Change object has a before property that lets you inspect what was
saved to Realtime Database before the event. The before property
returns a DataSnapshot where all methods (for example, val() and
exists()) refer to the previous value. You can read the new value
again by either using the original DataSnapshot or reading the after
property. This property on any Change is another DataSnapshot
representing the state of the data after the event happened.
The data that was deleted from the database is actually included in the call to your Cloud Function. You can get if from change.before.
exports.events = functions.database.ref('/events/{eventId}').onWrite(async (change, context) => {
const eventId = context.params.eventId
if (!change.after.exists() && change.before.exists()) {
//data removed
days = change.before.val().dayofweek;
...
})

How can I retrieve the UID of each document retrieved from FireStore DB when I subscribe my service method (performing the query)?

I am working on an Angular project retrieving data from Firebase FireStore database. It works fine but now I am finding problem trying to retrieve the documents UID. I will try to explain my situation in details.
Into my FireStore DB I have something like this:
So, as you can see, at the moment I only have a single collection named calendar containing some documents where each document represent an event on a calendar (but this detail is not so important now).
Into my Angular application I have a service class containing this method that simply perform a query to retrieve all the documents inside my calendar collection:
/**
* Return the list of all the work shift related to all the person in the calendar:
*/
getEvents(): Observable<any[]> {
this.items = this.db.collection('calendar').valueChanges();
return this.items;
}
So this method return an Observable of array on any objects.
Subscribing this Observable into my component I retrieve the list of documents stored into the calendar collection in FireStore.
I have done in this way (this is the code snippet into my component typescript file calling the previous service method):
this.eventService.getEvents().subscribe(events => { this.events = events.map((event) => {
//console.log("START: ", event.start);
var date = event.start.toDate()
var hour = date.getHours();
var startDateAsString = this.fromDateToString(date);
event.start = startDateAsString;
if(hour === 7) {
event['backgroundColor'] = 'red';
}
else if(hour === 15) {
event['backgroundColor'] = 'green';
}
else if(hour === 23) {
event['backgroundColor'] = 'black';
}
console.log("EVENT: ", event);
return event;
})});
So as you can see I am subscribing the previous service method performing the query and I "iterate" on the query resultset using the map() operator building my this.events array. It works fine.
My problem is: in this context how can I retrieve the UID of each documents retrieved by Firebase in order to add this information to the returned event variable?
valueChanges() does not include the id for the documents it receives. You need to use snapshotChanges() and then pipe the data to create an object.
I do something like this in my app
this.db.collection('collectionName').snapshotChanges().pipe(
map(snapshots => {
return snapshots.map(s => {
// if you log s here, you can look through the object
// payload.doc.data() should be the same as what valueChanges returns
// payload.doc.id will be the id
// merge them into a new object
return {...s.payload.doc.data(), id: s.payload.doc.id)}
})
}
);

delete data from firebase using key

This is my first time using firebase. My database looks like:enter image description here
I have the key and would like to remove the node for that key:
var dataKey = $("#trainClicked").attr("data-key");
var ref = database.ref("trains/" + changeTrain);
ref.on('value', function (snapshot) {
console.log(snapshot)
if (snapshot === null) {
console.log("does not exist")
} else {
return database.ref().remove(dataKey)
}
});
This removes the entire database and gives an error:
return database.ref().remove(dataKey)
I have read through firebase docs and through many posts here but I still cant get it to work. Thanks in advance.
Reference.remove() doesn't take any arguments, but instead removes the data at the reference you call it on. Since you're calling remove() on the root of the database, all data gets removed.
You're looking for ref.remove() or snapshot.ref.remove() here.
Simply run an empty .set() command on that node. That will delete everything. If you run an empty .set() you will delete your entire database. :-)
This is the code that works:
var dataKey = $("#train-clicked").attr("data-key");
var ref = database.ref("trains/" + dataKey)
ref.once('value', function (snapshot) {
if (snapshot === null) {
console.log("does not exist")
} else {
snapshot.ref.remove();
}
Changing the snapshot.ref.remove() line but also changing ref.on to ref.once.... when it was .on it worked once but it was giving an error because it was trying to read something that wasnt there any more (I think).

jQuery Ajax callback to a class method seemingly calling wrong instance

I have a Vue instance with a Vuex Store.
Vue components can call a method on the Vue instance to ensure certain objects are present in the Vuex store. Each object is stored as an instance of a class ApiObject. If only the object's ID is known the object will be pulled from the server with a jQuery Ajax request.
The following issue occurs:
I have two ApiObjects with their respective object IDs of "0d3f7f10" and "f6a7d150". The first one is already present in the Vuex store but the second one is only known by it's id, so an Ajax reqeuest is triggered.
The object with the id "f6a7d150" starts the ajax request and hits the correct endpoint (/api/v1/f6a7d150) and then hits the callback function, which is a method of the ApiObject class.
But when the callback is called, I'm all of a sudden in the wrong instance of ApiObject. I would expect that I'm calling the ApiObject "f6a7d150"'s callback method but I'm hitting "0d3f7f10"'s callback method.
That's the API call and callback methods:
refresh () {
console.log('Calling ' + this.id);
jQuery.ajax({
context: this,
url: this.url(),
method: 'GET',
success: this.handleApiResult
})
}
handleApiResult (result) {
console.log('Handling ' + this.id);
this.data = result['data'];
}
The expected console output would be:
Calling f6a7d150
Handling f6a7d150
But it actually is:
Calling f6a7d150
Handling 0d3f7f10
The result variable in handleApiResult holds the correct object with the ID "f6a7d150", so up until the API call we were in the correct instance.
When I dump the Vuex Store there are two objects with ID "0d3f7f10", one with data and the second one (which is the one we just pulled from the API) without data, so only it's ID is known.
The Vue components create objects in Vuex with these methods on my Vue instance. The console log reports, that objects with ID "f6a7d150" and "0d3f7f10" were created, so I have no idea, how there is no object with ID "f6a7d150" in my store.
ensureObject (type, id, data) {
if (!type || (!id && !data)) {
return;
}
if (!id) {
id = data.id;
}
if (this.$store.state[type].filter(o => o.id === id).length < 1) {
console.log("Creating " + id);
this.$store.state[type].push(new CiliatusObject(type, id, data));
}
},
ensureObjects (type, ids, data) {
if (!ids && !data) {
return;
}
if (!ids) {
data.forEach(obj => this.ensureObject(type, null, obj));
}
else {
let that = this;
ids.forEach(function (id) {
that.ensureObject(
type,
id,
data ? data.filter(o => o && o.id === id)[0] : undefined
)
});
}
}
Any suggestions would be greatly appreciated.
Alright I found it after banging my head against a wall for hours.
In a computed property of a Vue component, there was this line:
let obj = this.$store.state.filter(s => s.id = this.id);
Notice the =where you'd expect a ===.....

AngularJS and Restangular, trying to convert update method to API

I'm trying to convert my basic crud operations into an API that multiple components of my application can use.
I have successfully converted all methods, except the update one because it calls for each property on the object to be declared before the put request can be executed.
controller
$scope.update = function(testimonial, id) {
var data = {
name: testimonial.name,
message: testimonial.message
};
dataService.update(uri, data, $scope.id).then(function(response) {
console.log('Successfully updated!');
},
function(error) {
console.log('Error updating.');
});
}
dataService
dataService.update = function(uri, data, id) {
var rest = Restangular.one(uri, id);
angular.forEach(data, function(value, key) {
// needs to be in the format below
// rest.key = data.key
});
// needs to output something like this, depending on what the data is passed
// rest.name = data.name;
// rest.message = data.message;
return rest.put();
}
I tried to describe the problem in the codes comments, but to reiterate I cannot figure out how to generate something like rest.name = data.name; without specifying the name property because the update function shouldn't need to know the object properties.
Here is what the update method looked like before I started trying to make it usable by any of my components (this works)
Testimonial.update = function(testimonial, id) {
var rest = Restangular.one('testimonials', id);
rest.name = testimonial.name;
rest.message = testimonial.message;
return rest.put();
}
How can I recreate this without any specific properties parameters hard-coded in?
Also, my project has included lo-dash, if that helps, I don't know where to start with this problem. Thanks a ton for any advice!
Try like
angular.extend(rest,testimonial)
https://docs.angularjs.org/api/ng/function/angular.extend

Categories

Resources