delete data from firebase using key - javascript

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).

Related

Data in Firestore not updating

Here is a javascript function intending to perform an update on FireStore, which does not work.
I will be more that happy if anyone can see an issue in the code.
function makeUpdate(key,name) {
let theCollection = db.collection("InformationList"),
infoUnit = theCollection.doc(key).get().then(function(doc) {
if (doc.exists) {
console.log("infoUnit -name-:" + doc.get("name"));
console.log("infoUnit -telephone-:" + doc.get("telephone"));
let updateDico = {};
updateDico["name"] = name;
doc.update(updateDico);
} else {
console.log("embassyUpdate --> No such document!");
}
}).catch(err => {
console.log("Error getting documents (in makeUpdate)", err);
});
}
Apart from the fact that it does not perform the expected update, it prints three messages in the logs:
infoUnit -name-: some name
infoUnit -telephone-: some telephone number
Error getting documents (in makeUpdate)
From that I can see that a record is found in the database as expected. But at the same time an unknown error occurs.
There is no update() method on doc (which a DocumentSnapshot object). A DocumentSnapshot just contains the data read from get(). If you want to write data back into a document, you'll need to use a DocumentReference object, probably the same one you got when you called theCollection.doc(key).
There is no such method called update() which you can invoke on doc DataSnapshot object itself.
You'll have to use the set() method on the Document Reference which you get from doc.ref to update the reference.
This is how I've updated my data.
await db
.collection('collectionName')
.doc('documentId')
.update({
name: "Updated Name",
telephone: "0000000000"
});
You need to know document id and you can update your value like this.

MongoDB - Mongoose - TypeError: save is not a function

I am attempting to perform an update to a MongoDB document (using mongoose) by first using .findById to get the document, then updating the fields in that document with new values. I am still a bit new to this so I used a tutorial to figure out how to get it working, then I have been updating my code for my needs. Here is the tutorial: MEAN App Tutorial with Angular 4. The original code had a schema defined, but my requirement is for a generic MongoDB interface that will simply take whatever payload is sent to it and send it along to MongoDB. The original tutorial had something like this:
exports.updateTodo = async function(todo){
var id = todo.id
try{
//Find the old Todo Object by the Id
var oldTodo = await ToDo.findById(id);
}catch(e){
throw Error("Error occured while Finding the Todo")
}
// If no old Todo Object exists return false
if(!oldTodo){
return false;
}
console.log(oldTodo)
//Edit the Todo Object
oldTodo.title = todo.title
oldTodo.description = todo.description
oldTodo.status = todo.status
console.log(oldTodo)
try{
var savedTodo = await oldTodo.save()
return savedTodo;
}catch(e){
throw Error("And Error occured while updating the Todo");
}
}
However, since I don't want a schema and want to allow anything through, I don't want to assign static values to specific field names like, title, description, status, etc. So, I came up with this:
exports.updateData = async function(update){
var id = update.id
// Check the existence of the query parameters, If they don't exist then assign a default value
var dbName = update.dbName ? update.dbName : 'test'
var collection = update.collection ? update.collection : 'testing';
const Test = mongoose.model(dbName, TestSchema, collection);
try{
//Find the existing Test object by the Id
var existingData = await Test.findById(id);
}catch(e){
throw Error("Error occurred while finding the Test document - " + e)
}
// If no existing Test object exists return false
if(!existingData){
return false;
}
console.log("Existing document is " + existingData)
//Edit the Test object
existingData = JSON.parse(JSON.stringify(update))
//This was another way to overwrite existing field values, but
//performs a "shallow copy" so it's not desireable
//existingData = Object.assign({}, existingData, update)
//existingData.title = update.title
//existingData.description = update.description
//existingData.status = update.status
console.log("New data is " + existingData)
try{
var savedOutput = await existingData.save()
return savedOutput;
}catch(e){
throw Error("An error occurred while updating the Test document - " + e);
}
}
My original problem with this was that I had a lot of issues getting the new values to overwrite the old ones. Now that that's been solved, I am getting the error of "TypeError: existingData.save is not a function". I am thinking the data type changed or something, and now it is not being accepted. When I uncomment the static values that were in the old tutorial code, it works. This is further supported by my console logging before and after I join the objects, because the first one prints the actual data and the second one prints [object Object]. However, I can't seem to figure out what it's expecting. Any help would be greatly appreciated.
EDIT: I figured it out. Apparently Mongoose has its own data type of "Model" which gets changed if you do anything crazy to the underlying data by using things like JSON.stringify. I used Object.prototype.constructor to figure out the actual object type like so:
console.log("THIS IS BEFORE: " + existingData.constructor);
existingData = JSON.parse(JSON.stringify(update));
console.log("THIS IS AFTER: " + existingData.constructor);
And I got this:
THIS IS BEFORE: function model(doc, fields, skipId) {
model.hooks.execPreSync('createModel', doc);
if (!(this instanceof model)) {
return new model(doc, fields, skipId);
}
Model.call(this, doc, fields, skipId);
}
THIS IS AFTER: function Object() { [native code] }
Which showed me what was actually going on. I added this to fix it:
existingData = new Test(JSON.parse(JSON.stringify(update)));
On a related note, I should probably just use the native MongoDB driver at this point, but it's working, so I'll just put it on my to do list for now.
You've now found a solution but I would suggest using the MongoDB driver which would make your code look something along the lines of this and would make the origional issue disappear:
// MongoDB Settings
const MongoClient = require(`mongodb`).MongoClient;
const mongodb_uri = `mongodb+srv://${REPLACE_mongodb_username}:${REPLACE_mongodb_password}#url-here.gcp.mongodb.net/test`;
const db_name = `test`;
let db; // allows us to reuse the database connection once it is opened
// Open MongoDB Connection
const open_database_connection = async () => {
try {
client = await MongoClient.connect(mongodb_uri);
} catch (err) { throw new Error(err); }
db = client.db(db_name);
};
exports.updateData = async update => {
// open database connection if it isn't already open
try {
if (!db) await open_database_connection();
} catch (err) { throw new Error(err); }
// update document
let savedOutput;
try {
savedOutput = await db.collection(`testing`).updateOne( // .save() is being depreciated
{ // filter
_id: update.id // the '_id' might need to be 'id' depending on how you have set your collection up, usually it is '_id'
},
$set: { // I've assumed that you are overwriting the fields you are updating hence the '$set' operator
update // update here - this is assuming that the update object only contains fields that should be updated
}
// If you want to add a new document if the id isn't found add the below line
// ,{ upsert: true }
);
} catch (err) { throw new Error(`An error occurred while updating the Test document - ${err}`); }
if (savedOutput.matchedCount !== 1) return false; // if you add in '{ upsert: true }' above, then remove this line as it will create a new document
return savedOutput;
}
The collection testing would need to be created before this code but this is only a one-time thing and is very easy - if you are using MongoDB Atlas then you can use MongoDB Compass / go in your online admin to create the collection without a single line of code...
As far as I can see you should need to duplicate the update object. The above reduces the database calls from 2 to one and allows you to reuse the database connection, potentially anywhere else in the application which would help to speed things up. Also don't store your MongoDB credentials directly in the code.

Firebase Update just a Parent Node

This is a small question and if need be I'll just rewrite everything, but I want to save myself the work.
I have a structure that looks like users/usernames/<someUN>/. I checked out the Firebase documentation but I couldn't find examples of how to update in a 'tight' tree.
Now if I want to change <someUN>, you can see the problem
this.database.ref('users/usernames/' + this.UN).update({
username: newUsernameVariable
})
I would have to restructure an unchangable value and do something like users/usernames/<userID>/username/<username> but
it goes against denormalizing the database and
I already have a tree holding uids/<uid>/usernames/<UN>, so that would be extra redundant
Now if you tried to move the ref up a notch:
this.database.ref('users/usernames').update({
this.UN: newUsernameVariable
})
This is very close to what I want but unfortunately is not valid JSON. The left hand side is not converted to string. I've tried doing this
var UNJSON = JSON.stringify(this.UN);
this.database.ref('users/usernames/').update({
UNJSON: newUsername
});
But it won't work, just treats UNJSON as a word
EDIT:
I've changed it to
var updates = {};
updates[this.UN] = newUsername;
this.database.ref('users/usernames').update(updates);
Which almost works, but now the children node are replaced!
I've changed the question of this title because essentially I've gotten to the point where I have something like users/usernames/myawesomeusername/{manychildren} and I want to keep the children while editing myawesomeusername.
EDIT 2: this.UN is populated in onAuthStateChanged by the time it hits the update code. Here is the setting of this.UN
// UN is a global read/write username string that persists throughout the session.
// SETTING THE VALUE OF this.UN WITH UID
if(this.UN == undefined) {
console.log('this.UN was null. Fetch the real one with UID from the database');
this.database.ref('uids/' + user.uid).once('value', function(snapshot){
this.UN = snapshot.val().username;
console.log('Grabbed from snapshot.username');
if(this.UN == undefined) {
console.log('Impossible error');
}
}.bind(this)).catch(function(err){
console.log('Error obtaining userID from database', err);
this.UN = user.displayName || "User" + user.uid;
}.bind(this));
} else {
console.log(this.UN);
}
I use this.UN to handle any time I need the username for the rest of the app.

firebase - handle no data from snapshot

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...

getting single objects out of $angularfire/$firebase

I am trying to follow a tutorial on lynda.com which uses angularfire (angularjs firebase) except it uses stuff like $firebase.$asObject and such, which is now obsolete. I tried to look at the documentation as well as some other SOF questions, and I finally found something that worked, but it looks ugly and seems quite inefficient since the only way I found for it to work is to iterate through all the objects in an array returned from the database. This array holds all the users which are registered. This is how I got it to work, but can someone tell me the correct way to do it, because this does not seem like it should be it.
var ref = new Firebase(FIREBASE_URL);
var auth = firebaseAuth(ref);
auth.$onAuth(function(authUser){
if(authUser){
var ref = new Firebase(FIREBASE_URL + 'users/');
var stuff = firebaseArray(ref);
ref.on('value', function(snapshot) {
if(snapshot.val() !== null) {
var keys = Object.keys(snapshot.val());
for(var key in keys){
if(keys.hasOwnProperty(key)){
if(authUser.uid === snapshot.val()[keys[key]].registeredUser){
rootScope.currentUser = snapshot.val()[keys[key]];
}
}
}
} else {
console.log('location does not exist');
}
});
var user = firebaseObject(ref);
//console.log(user);
rootScope.currentUser = user;
} else {
rootScope.currentUser = '';
}
});
Here is what my firebase forge looks like:
Thank you in advance!
It is usually helpful to store user data like proposed in https://www.firebase.com/docs/web/guide/user-auth.html#section-storing.
You need to use the unique ID as the key for the user object, so you don't have to iterate over all users to search for it. The unique ID is part of the auth data, see https://www.firebase.com/docs/web/guide/user-auth.html#section-monitoring-authentication).

Categories

Resources