Firebase实时数据库中是否可以重命名一个键?

29

我想知道是否有一种方法可以更新键值?

让我们使用以下数据:

我的数据

我正在使用set()来写入数据。现在,我希望用户编辑他们的bookTitle,并且需要在两个位置上更改它。我尝试使用update(),但似乎无法使其正常工作。我只能编辑bookInfo中的bookTitle而不能编辑books中的bookTitle

移动不是选项,因为这会删除bookData。 我还尝试使用push()编写,但是我不能正确搜索,因为我没有pushID(我需要搜索,因为用户不能使用相同名称拥有两本书)

那么,是否有一种方法可以更新键值? 或者,有更好的方法吗?我接受建议。谢谢!

更新:这是我目前用于更新bookInfo内书名的方法:

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

firebase.database().ref('books/' + bookName + '/bookInfo').update({
    bookTitle : bookName
});

我在解析您的描述时遇到了问题。您能否包含您尝试过但未能正常工作的代码?这样可能更容易解析。 - Frank van Puffelen
这个问题不是已经在这里回答了吗?:https://dev59.com/SF4b5IYBdhLWcg3wchXs - DavidTaubmann
5个回答

26

我想我理解你的意图了。Firebase没有通过更新来实现重命名路径部分的概念。相反,您需要完全删除现有节点并重新创建它。您可以像这样完成:

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);
});

这将从books/oldTitle中删除信息,并用新标题在books/newTitle中重新填充。

注意:这依赖于读取数据,然后执行第二次异步更新。如果可能会有多个用户同时操作相同的数据,则可能会导致问题。您可以使用事务以原子方式执行此操作,但如果/books是具有许多节点的顶级资源,则可能会导致性能问题。

如果只有一个人有可能编辑数据,则上述解决方案是可行的。如果不是,请考虑使用非用户控制的标识符,例如推送ID。


在这个例子中,根节点只是一个分数。整个数据库的结构是 root /writers/<userID>/books/bookTitle/bookInfo>,因此只有一个用户会编辑这些信息。非常感谢。 - Luis Rodriguez
有人能用Java解释一下吗? - E.Akio
1
@frank-van-puffelen,我建议将此功能添加到FireBase实时数据库的控制台中,因为我最近经常使用它来重命名键上的特殊情况。 - DavidTaubmann
@frankvanpuffelen 我建议将此功能添加到 Firebase 实时数据库的控制台中,因为最近我经常使用它来重命名键上的特殊情况。 - DavidTaubmann
如果我们有权重命名键,那就更好了。 - Lutaaya Huzaifah Idris

18
你可以将整个数据库导出为JSON格式,然后在你喜欢的编辑器中重命名它,通过控制台窗口右上方的导入/导出选项将其重新导入到Firebase中。 在此输入图像描述

这对于任何规模的数据库或正在使用的数据库来说,似乎都是一个非常不切实际的想法(您可能会在编辑时丢失正在进行的更改)。 - André Kool
4
这是我以前使用的解决方案。为了避免下载整个数据库,你可以只下载、修改和上传受影响的子部分。 - DavidTaubmann

1
我仍然会使用push(),这是在Firebase中将多个子对象存储在类别节点下的正确方法。对于搜索,您是否考虑在客户端上执行此操作?例如,您可以将所有书籍对象保存在books节点下,并在需要时检索这些对象以进行本地搜索。
另外,正如ZenPylon提到的那样,push()会为您提供一个唯一的ID,您还可以将其分配为每个书籍对象的属性,以便每本书都有一个引用,指向其在数据库中的存储位置。

1
值得注意的一点是,您可以从push()函数中获取唯一键。
var booksRef = firebaseRef.database().ref('books');
var newBookRef = booksRef.push(myBookData);
var bookKey = newBookRef.key;

来源: Firebase文档 - push()

从你的截图中我无法确定第二个bookTitle实例在哪里(它是截图中的根元素吗?),但如果你不想使用push(),你可以获取该位置的数据,使用remove(),然后再次调用set(),这次更新书名。类似于:

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

});

是的,它在根目录下。因此,将book1中的所有信息移动到名为“NewTitle”的新子级别中,对吗? - Luis Rodriguez
啊,另外,你需要在之后使用 bookRef.remove() 来清除旧的引用。 - ZenPylon

1

我很喜欢 Michael Bleigh 的回答,但是...

当我将键从一个级别移动到另一个级别时,它限制了我深入的范围,因此我更好地编写了这个函数,甚至允许您通过简单更改第三个参数来复制(0)或移动(1)完整的键:

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);
    });
  });
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接