当前位置: 首页 > 知识库问答 >
问题:

用于文件上传的Firebase实时数据库结构

安星汉
2023-03-14

我正在使用AngularFire2进行我的第一个Firebase项目。下面是我的学习项目的总体设计。

  • 用户上传照片,并将其作为图片存储在 Firebase 存储中。
  • 上传的照片列在主页上,根据时间戳进行排序。

下面是我现在开始时的结构。但是我在做连接时感到困难。我应该能够获取每个上传的用户详细信息并能够按时间戳对上传进行排序。

User:
- Name
- Email
- Avatar

Uploads:
  - ImageURL
  - User ID
  - Time

我读过一些博客,将数据结构去规范化。对于我的给定方案,如何最好地重新建模我的数据库结构?

在新提出的解决方案中创建一些示例数据的任何示例都将有助于我的理解。

一旦图像上传完成,我调用下面的代码在数据库中创建一个条目。

addUpload(image: any): firebase.Promise<any> {
  return firebase.database().ref('/userUploads').push({
    user: firebase.auth().currentUser.uid,
    image: image,
    time: new Date().getTime()
  });
}

我正在尝试加入2实体,如下所示。我不确定如何有效和正确地做到这一点。

 getUploads(): any {
    const rootDef = this.db.database.ref();
    const uploads = rootDef.child('userUploads').orderByChild('time');

    uploads.on('child_added',snap => {
      let userRef =rootDef.child('userProfile/' + snap.child('user').val());
      userRef.once('value').then(userSnap => {
        ???? HOW TO HANDLE HERE
      });
    });

return ?????;
}

我想得到一个最终的列表,其中包含所有上传细节和每个上传的相应用户数据。

共有2个答案

夹谷星剑
2023-03-14

我根据弗兰克斯的回答做了下面的工作,它是有效的。我不确定这是否是处理大量数据的最佳方式。

getUploads() {

    return new Promise((resolve, reject) => {
      const rootDef = this.db.database.ref();
      const uploadsRef = rootDef.child('userUploads').orderByChild('time');
      const userRef = rootDef.child("userProfile");
      var uploads = [];

      uploadsRef.once("value").then((uploadSnaps) => {

        uploadSnaps.forEach((uploadSnap) => {

          var upload = uploadSnap.val();

          userRef.child(uploadSnap.val().user).once("value").then((userSnap) => {
            upload.displayName = userSnap.val().displayName;
            upload.avatar = userSnap.val().avatar;
            uploads.push(upload);
          });
        });

      });

      resolve(uploads);
    });

}
党权
2023-03-14

如果从头开始编写,这种类型的连接总是很棘手。但我会试着带你通过它。我使用这个JSON来回答:

{
  uploads: {
    Upload1: {
      uid: "uid1",
      url: "https://firebase.com"
    },
    Upload2: {
      uid: "uid2",
      url: "https://google.com"
    }
  },
  users: {
    uid1: {
      name: "Purus"
    },
    uid2: {
      name: "Frank"
    }
  }
}

我们采取了三步走的方法:

    < li >从< code >上传加载数据 < li >从< code>users加载该数据的用户 < li >将用户数据加入到上传数据中

您的代码正在尝试返回一个值。由于数据是从Firebase异步加载的,因此在您的返回语句执行时它还不可用。这为您提供了两个选项:

  1. 将回调传递到<code>getUploads()
  2. 从<code>getUploads()

我将在这里使用promise,因为代码已经够难了。

function getUploads() {
  return ref.child("uploads").once("value").then((snap) => {
    return snap.val();
  });
}

这应该是相当可读的:我们加载所有上传,一旦加载,我们就返回值。

getUploads().then((uploads) => console.log(uploads));

将打印:

{
  Upload1 {
    uid: "uid1",
    url: "https://firebase.com"
  },
  Upload2 {
    uid: "uid2",
    url: "https://google.com"
  }
}

现在,在下一步中,我们将为每次上传加载用户。对于此步骤,我们不再返回上传,而只是返回每个上传的用户节点:

function getUploads() {
  return ref.child("uploads").once("value").then((snap) => {
    var promises = [];
    snap.forEach((uploadSnap) => {
      promises.push(
         ref.child("users").child(uploadSnap.val().uid).once("value")
      );
    });
    return Promise.all(promises).then((userSnaps) => {
      return userSnaps.map((userSnap) => userSnap.val());
    });
  });
}

您可以看到,我们对上传进行了循环,并创建了一个为该上传加载用户的promise。然后,我们返回< code>Promise.all(),这确保只有在加载了所有用户后,才会调用它的< code>then()。

现在呼叫

getUploads().then((uploads) => console.log(uploads));

打印:

[{
  name: "Purus"
}, {
  name: "Frank"
}]

因此,我们获得了一组用户,每个上传一个用户。请注意,如果同一用户发布了多个上传,您将在此数组中多次获得该用户。在实际的生产应用中,您希望消除用户的重复。但是这个答案已经变得足够长了,所以我把它留给读者作为练习......

最后一步是从前面两个步骤中获取数据并将其连接在一起。

function getUploads() {
  return ref.child("uploads").once("value").then((snap) => {
    var promises = [];
    snap.forEach((uploadSnap) => {
      promises.push(
         ref.child("users").child(uploadSnap.val().uid).once("value")
      );
    });
    return Promise.all(promises).then((userSnaps) => {
      var uploads = [];
      var i=0;
      snap.forEach((uploadSnap) => {
        var upload = uploadSnap.val();
        upload.username = userSnaps[i++].val().name;
        uploads.push(upload);
      });
      return uploads;
    });
  });
}

您将看到我们在<code>promise中添加了<code>then()。all()call,在所有用户加载后调用。在这一点上,我们有用户和他们的上传,所以我们可以将他们连接在一起。由于我们以与上传相同的顺序加载用户,因此我们可以通过他们的索引(i)加入他们。一旦您消除了用户的重复,这将有点棘手。

现在,如果您使用以下方式调用代码:

getUploads().then((uploads) => console.log(uploads));

它打印:

[{
  uid: "uid1",
  url: "https://firebase.com",
  username: "Purus"
}, {
  uid: "uid2",
  url: "https://google.com",
  username: "Frank"
}]

具有创建该上载的用户的名称的上载数组。

每个步骤的工作代码在https://jsbin.com/noyemof/edit?js安慰

 类似资料:
  • 我搜索了Firebase:只读&非实时模式,为提高浏览器性能而激活,以及其他一些相关站点。我找不到实时数据库的最大文件限制大小。 我知道,这是非常明显的,我们放的JSON文件越小,我们就越实时。请不要评论说“使用小型的实时数据库”。我想知道实时数据库的最大文件大小。

  • 3.移除值事件侦听器和脱机的区别。

  • 我试图让我的flutter应用程序在浏览器中工作,它依赖于Firebase_database。没有关于如何做到这一点的文档,但我根据firebase_core和firebase_auth文档做了一些假设: > https://github.com/firebaseextended/flutterfire/tree/master/packages/firebase_core/firebase_cor

  • 我在一个Android应用程序中使用Firebase数据库,每次用户启动时,我都会在数据库中存储一些值,为此我会执行以下操作: 正如您在子方法中看到的,如果称为“usrId”,它将创建usrId目录,并在其中添加所有neccesary信息。但是我想为每个用户创建目录,所以我尝试传递usrId变量作为参数。但它不起作用。当我调试代码时,调试器说本地var usrId无法识别,我的问题是如何在Fire

  • 我正在尝试上传图像到firebase,以及其他字符串和双数据类型。 我现在正在考虑两个选项,一个是上载imageUrl到firebase实时数据库,当我检索它时,我将检索一个imageUrl并将其转换为图像。 谢谢你的帮助!我很感激。