29

I was wondering, is there a way to update the key value?

Let´s use the following data:

my data

I am using set() to write the data. Now, I want the user to edit their bookTitle and it needs to change on both places. I tried using update() but I can´t seem to make it work. I can only edit the bookTitle in bookInfo NOT on books.

Moving is not an option because it will erase the bookData. I also tried writing using push() but then, I can´t search properly because I don´t have the pushID (I need the search because users can't have two books with the same name)

So, is there a way to update the key value? or, is there a better approach to this? I accept suggestions. Thank you!

Update: This is what I´m currently using to update the book title inside bookInfo

var bookName = document.getElementById('bookName').value;

firebase.database().ref('books/' + bookName + '/bookInfo').update({
    bookTitle : bookName
});
Michael Bleigh
  • 25,334
  • 2
  • 79
  • 85
Luis Rodriguez
  • 503
  • 1
  • 6
  • 12

5 Answers5

26

I think I see what you're trying to do. Firebase doesn't have the concept of "renaming" a part of the path via update. Instead you will have to completely remove the existing node and recreate it. You can do that like so:

var booksRef = firebase.database().ref('books');
booksRef.child(oldTitle).once('value').then(function(snap) {
  var data = snap.val();
  data.bookInfo.bookTitle = newTitle;
  var update = {};
  update[oldTitle] = null;
  update[newTitle] = data;
  return booksRef.update(update);
});

This will remove the info from books/oldTitle and re-populate it with a new title in books/newTitle.

Caveat: This relies on reading the data and then performing a second async update. If you are likely to have multiple users operating on the same data at the same time this could cause issues. You could use a transaction to do this atomically but if /books is a top-level resource with many nodes that may cause performance problems.

If one person is likely to edit the data at a time, the above solution is fine. If not, you may want to consider using a non-user-controlled identifier such as a push id.

Michael Bleigh
  • 25,334
  • 2
  • 79
  • 85
  • The root in the example was just a fraction. The whole db is structured `root /writers//books/bookTitle/bookInfo>` so, only one user will edit the info. Thank you very much. – Luis Rodriguez Aug 23 '16 at 18:13
  • Can anyone explain it with Java plz? – E.Akio Feb 03 '19 at 16:47
  • 1
    @frank-van-puffelen I would suggest this to be added to the console of the FireBase Realtime Database, I've been using it lots lately to rename special cases on the keys. – DavidTaubmann Jul 22 '19 at 01:38
  • @frankvanpuffelen I would suggest this to be added to the console of the FireBase Realtime Database, I've been using it lots lately to rename special cases on the keys. – DavidTaubmann Jul 22 '19 at 01:38
  • It would have been better if we had the mandate to rename the key – Lutaaya Huzaifah Idris Dec 27 '19 at 14:19
18

You can export all the database as JSON, rename it in your favorite editor import it again to firebase via import/export option on the top right in the console windowenter image description here

Rami
  • 224
  • 2
  • 4
  • This sould like a very unpractical idea for any database above a certain size or a database that is being used (you might lose changes that are being made while you edit). – André Kool Jul 21 '19 at 10:25
  • 4
    This was the solution I was using before. To avoid downloading the entire database you can just download + modify + upload only the sub-section affected. – DavidTaubmann Jul 22 '19 at 01:40
1

One thing worth noting is that you can grab the unique key from the push() function.

var booksRef = firebaseRef.database().ref('books');
var newBookRef = booksRef.push(myBookData);
var bookKey = newBookRef.key;

Source: Firebase Docs - push()

I can't tell from your screenshot where the second instance of bookTitle is (is it the root element in the screenshot?), but if you don't want to use push(), you could grab the data at that location, remove(), and then call set() again, this time with the updated book title. Something like:

var bookRef = firebaseRef.database().ref('path/to/books/book1');

bookRef.on('value', function(snapshot) {
    var bookData = snapshot.val();
    var newData = {};
    var newTitle = 'NewTitle';

    bookData.bookInfo.bookTitle = newTitle;
    newData[newTitle] = bookData;
    firebaseRef.database().ref('path/to/books/' + newTitle).set(newData);

});
Blake Lockley
  • 2,931
  • 1
  • 17
  • 30
ZenPylon
  • 518
  • 4
  • 11
1

I would still use push(), that's really the proper way to store multiple child objects under category-node in firebase I think. For searching, have you thought about doing this on the client side? For example you can save all your book objects under books node, and retrieve those to search locally when you need to.

Also as ZenPylon mentioned, push() gives you a unique id that you can also assign as a prop to each book object so each book has a reference to where it is stored in the database.

tetutato
  • 638
  • 5
  • 16
1

I liked a lot Michael Bleigh's answer BUT...

It was restricting me the scope of deepness when moving keys from one level to another, so I better made this function which even allows you to duplicate (0) or move (1) the complete key by simply changing the third argument:

function mvFBkey(rtOrgn,rtDstn,rem){
  firebase.database().ref(rtOrgn).once('value').then(function(snap) {
    return firebase.database().ref(rtDstn).set(snap.val(),function(){
        if(rem)firebase.database().ref(rtOrgn).set(null);
    });
  });
}
DavidTaubmann
  • 3,223
  • 2
  • 34
  • 43