【发布时间】:2017-12-11 20:29:52
【问题描述】:
我目前正在使用 Ionic CLI 3.19 和 Cordova CLI 7.1.0 (@ionic-app-script 3.1.4)
我目前面临的问题是,每次相关数据从其他地方发生变化时,我都应该同时更新好友节点值。我想通过一些屏幕截图来阐明我的目标,以使其更加清晰。
从下图中可以看出,每个子节点都包含一个用户数组,其中用户 id 作为好友节点的键。我存储为数组的原因是因为每个用户可以有很多朋友。 在此示例中,Jeff Kim 有一个朋友 John Doe,反之亦然。
当用户节点中的数据由于某种原因发生变化时,我希望朋友节点中的相关数据也希望它们也被更新。
例如,当 Jeff Kim 更改他的头像或 statusMessage 时,所有与 Jeff Kim 的 uid 匹配的朋友节点中的相同 uid 都需要根据用户的更改进行更新。
user-service.ts
constructor(private afAuth: AngularFireAuth, private afDB: AngularFireDatabase,){
this.afAuth.authState.do(user => {
this.authState = user;
if (user) {
this.updateOnConnect();
this.updateOnDisconnect();
}
}).subscribe();
}
sendFriendRequest(recipient: string, sender: User) {
let senderInfo = {
uid: sender.uid,
displayName: sender.displayName,
photoURL: sender.photoURL,
statusMessage: sender.statusMessage,
currentActiveStatus: sender.currentActiveStatus,
username: sender.username,
email: sender.email,
timestamp: Date.now(),
message: 'wants to be friend with you.'
}
return new Promise((resolve, reject) => {
this.afDB.list(`friend-requests/${recipient}`).push(senderInfo).then(() => {
resolve({'status': true, 'message': 'Friend request has sent.'});
}, error => reject({'status': false, 'message': error}));
});
}
fetchFriendRequest() {
return this.afDB.list(`friend-requests/${this.currentUserId}`).valueChanges();
}
acceptFriendRequest(sender: User, user: User) {
let acceptedUserInfo = {
uid: sender.uid,
displayName: sender.displayName,
photoURL: sender.photoURL,
statusMessage: sender.statusMessage,
currentActiveStatus: sender.currentActiveStatus,
username: sender.username,
email: sender.email
}
this.afDB.list(`friends/${sender.uid}`).push(user);
this.afDB.list(`friends/${this.currentUserId}`).push(acceptedUserI
this.removeCompletedFriendRequest(sender.uid);
}
根据我刚刚看到的这个clip,看起来我做了一个名为Denormalization 的事情,解决方案可能是使用Multi-path updates 来一致地更改数据。 Data consistency with Multi-path updates。但是,要完全理解并开始编写一些代码有点棘手。
我做了一些练习,以确保在不调用 .update 方法两次的情况下更新多个位置的数据。
// I have changed updateUsername method from the code A to code B
// Code A
updateUsername(username: string) {
let data = {};
data[username] = this.currentUserId;
this.afDB.object(`users/${this.currentUserId}`).update({'username': username});
this.afDB.object(`usernames`).update(data);
}
// Code B
updateUsername(username: string) {
const ref = firebase.database().ref();
let updateUsername = {};
updateUsername[`usernames/${username}`] = this.currentUserId;
updateUsername[`users/${this.currentUserId}/username`] = username;
ref.update(updateUsername);
}
我并不是说这是一个完美的代码。但我试图自己解决这个问题,这就是我到目前为止所做的。
假设我目前以 Jeff 的身份登录。
当我运行此代码时,朋友节点中与 Jeff 关联的所有数据都会更改,同时用户节点中 Jeff 的数据也会同时更新。
代码需要由其他 Firebase 专家改进,并且应该在真实的测试代码上进行测试。
根据以下thread、once('value'(一般来说,这对于使用 Firebase 获得最佳性能来说是个坏主意)。 我应该找出这不好的原因。
friend.ts
getFriendList() {
const subscription = this.userService.getMyFriendList().subscribe((users: any) => {
users.map(u => {
this.userService.testMultiPathStatusMessageUpdate({uid: u.uid, statusMessage: 'Learning Firebase:)'});
});
this.friends = users;
console.log("FRIEND LIST@", users);
});
this.subscription.add(subscription);
}
user-service.ts
testMultiPathStatusMessageUpdate({uid, statusMessage}) {
if (uid === null || uid === undefined)
return;
const rootRef = firebase.database().ref();
const query = rootRef.child(`friends/${uid}`).orderByChild('uid').equalTo(this.currentUserId);
return query.once('value').then(snapshot => {
let key = Object.keys(snapshot.val());
let updates = {};
console.log("key:", key);
key.forEach(key => {
console.log("checking..", key);
updates[`friends/${uid}/${key}/statusMessage`] = statusMessage;
});
updates[`users/${this.currentUserId}/statusMessage`] = statusMessage;
return rootRef.update(updates);
});
}
以下代码在将状态更新为在线但不离线时可以正常工作。
我认为这不是正确的方法。
updateOnConnect() {
return this.afDB.object('.info/connected').valueChanges()
.do(connected => {
let status = connected ? 'online' : 'offline'
this.updateCurrentUserActiveStatusTo(status)
this.testMultiPathStatusUpdate(status)
})
.subscribe()
}
updateOnDisconnect() {
firebase.database().ref().child(`users/${this.currentUserId}`)
.onDisconnect()
.update({currentActiveStatus: 'offline'});
this.testMultiPathStatusUpdate('offline');
}
private statusUpdate(uid, status) {
if (uid === null || uid === undefined)
return;
let rootRef = firebase.database().ref();
let query = rootRef.child(`friends/${uid}`).orderByChild('uid').equalTo(this.currentUserId);
return query.once('value').then(snapshot => {
let key = Object.keys(snapshot.val());
let updates = {};
key.forEach(key => {
console.log("checking..", key);
console.log("STATUS:", status);
updates[`friends/${uid}/${key}/currentActiveStatus`] = status;
});
return rootRef.update(updates);
});
}
testMultiPathStatusUpdate(status: string) {
this.afDB.list(`friends/${this.currentUserId}`).valueChanges()
.subscribe((users: any) => {
users.map(u => {
console.log("service U", u.uid);
this.statusUpdate(u.uid, status);
})
})
}
它确实在控制台中显示offline,但更改不会出现在 Firebase 数据库中。
有人可以帮助我吗? :(
【问题讨论】:
-
对于“新”用户来说,这是一个格式和书面非常好的问题:) 我希望有人可以帮助你!欢迎使用 Stack Overflow。
-
@cramopy 感谢您的评论。我真的希望如此。目前,我正在阅读这个thread 但我的问题有点棘手。不确定该线程是否可以帮助我。
标签: firebase firebase-realtime-database ionic2 ionic3 angularfire2