我正在使用AngularFire2处理我的第一个Firebase项目。以下是我的学习项目的总体设计。
以下是我刚开始时的结构。但是在加入时我感到很困难。我应该能够获得每次上传的用户详细信息,并能够按时间戳排序上传。
addUpload(image: any): firebase.Promise<any> {
return firebase.database().ref('/userUploads').push({
user: firebase.auth().currentUser.uid,
image: image,
time: new Date().getTime()
});
}
我读了几篇博客,对数据结构进行了规范化。对于我给定的场景,我如何才能最好地重新建模我的数据库结构?
在新提议的解决方案中创建一些示例数据的任何示例都非常适合我的理解。
图片上传完成后,我调用以下代码在数据库中创建一个条目。
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个实体,如下所示。我不知道如何有效和正确地做到这一点。
var MyBlob = new Blob(['content'], {type : 'text/plain'});
console.log(MyBlob instanceof Blob) // true
我想获得最终列表,其中包含每次上传的所有上传详细信息及其相应的用户数据。
答案 0 :(得分:2)
如果从头开始编写,这种类型的连接总是很棘手。但我会试着引导你完成它。我使用这个JSON作为我的答案:
{
uploads: {
Upload1: {
uid: "uid1",
url: "https://firebase.com"
},
Upload2: {
uid: "uid2",
url: "https://google.com"
}
},
users: {
uid1: {
name: "Purus"
},
uid2: {
name: "Frank"
}
}
}
我们采取三步走法:
uploads
users
uploads
您的代码正在尝试返回值。由于数据是从Firebase异步加载的,因此在执行return
语句时它仍然无法使用。这给了你两个选择:
getUploads()
,然后在数据加载后调用。getUploads()
返回一个在数据加载后解析的承诺。我将在这里使用promises,因为代码已经足够困难了。
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"
}
}
users
现在,在下一步中,我们将为每次上传加载用户。对于此步骤,我们不再返回上传内容,只是每次上传的用户节点:
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.all()
,确保只有在加载所有用户后才会调用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;
});
});
}
您会看到我们在then()
调用中添加了Promise.all()
,该调用会在所有用户加载后调用。此时我们同时拥有用户及其上传内容,因此我们可以将它们连接在一起。由于我们按照与上传相同的顺序加载用户,因此我们可以按索引(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,console
答案 1 :(得分:0)
我根据弗兰克斯的回答做了以下事情并且它有效。我不确定这是否是处理大量数据的最佳方式。
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);
});
}