我目前正在使用Ionic CLI 3.19和Cordova CLI 7.1.0 (@离子型应用程序-脚本3.1.4)
我目前面临的问题是,每次相关数据从其他地方更改时,我都应该同时更新朋友节点值。我想用一些截图来澄清我的目标,以使它更清楚。
从下面的图像中可以看到,每个子节点都由一个用户数组组成,其中有一个用户id作为好友节点的键。我之所以将其存储为数组,是因为每个用户都可能有许多朋友。在本例中,Jeff有一个朋友,即John,反之亦然。

当用户节点中的数据因某种原因而更改时,我希望朋友节点中的相关数据也能被更新。
例如,当Jeff更改了他的配置文件照片或statusMessage时,与Jeff的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);
}根据我刚才看到的这个剪辑,看起来我做了一些名为Denormalization的事情,解决方案可能是使用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在用户节点中的数据也会同时更新。
代码需要由其他的防火墙专家来改进,并且应该在真正的测试代码上进行测试。
根据下面的线程,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数据库中。
,有人能帮我吗?:(
发布于 2017-12-11 01:31:42
我认为您这样做是正确的,并且您的多路径更新方向是正确的。但假设有几个用户可以有几个朋友,我就错过了朋友表中的一个循环。
您应该有表users、friends和userFriend。最后一个表就像在friends中查找用户的快捷方式,您需要迭代每个朋友以找到需要更新的用户。
我在我的first_app_example角度4+火力基础上做了一个不同的方法。我从客户端删除了这个过程,并通过云函数中的onUpdate()将它添加到服务器中。
在代码波纹管中,当用户更改名称时,云函数将在用户已经编写的每个评论中执行和更新名称。在我的例子中,客户端不知道非正规化。
//Executed when user.name changes
exports.changeUserNameEvent = functions.database.ref('/users/{userID}/name').onUpdate(event =>{
let eventSnapshot = event.data;
let userID = event.params.userID;
let newValue = eventSnapshot.val();
let previousValue = eventSnapshot.previous.exists() ? eventSnapshot.previous.val() : '';
console.log(`[changeUserNameEvent] ${userID} |from: ${previousValue} to: ${newValue}`);
let userReviews = eventSnapshot.ref.root.child(`/users/${userID}/reviews/`);
let updateTask = userReviews.once('value', snap => {
let reviewIDs = Object.keys(snap.val());
let updates = {};
reviewIDs.forEach(key => { // <---- note that I loop in review. You should loop in your userFriend table
updates[`/reviews/${key}/ownerName`] = newValue;
});
return eventSnapshot.ref.root.update(updates);
});
return updateTask;
});编辑
问:我是否正确地构造了朋友节点
我更喜欢复制(去修饰)只复制我更经常需要的信息。按照这个想法,您应该复制“userName”和“photoURL”。您可以通过以下两个步骤访问所有朋友的信息:
let friends: string[];
for each friend in usrService.getFriend(userID)
friends.push(usrService.getUser(friend))问:你的意思是我应该创建一个查找表?
在你的问题中提到的剪辑,David给了我们一个如何去造势的例子。原来他有users和events。在非正规化中,他创建了类似于vlookup的eventAttendees (就像您难过)。
问:你能举个例子吗?
好的。我删除了一些用户信息,并添加了一个额外的字段friendshipTypes
users
xxsxaxacdadID1
currentActiveStatus: online
email: zinzzkak@gmail.com
gender: Male
displayName: Jeff Kim
photoURL: https://firebase....
...
trteretteteeID2
currentActiveStatus: online
email: hahehahaheha@gmail.com
gender: Male
displayName: Joeh Doe
photoURL: https://firebase....
...
friends
xxsxaxacdadID1
trteretteteeID2
friendshipTypes: bestFriend //<--- extra information
displayName: Jeff Kim
photoURL: https://firebase....
trteretteteeID2
xxsxaxacdadID1
friendshipTypes: justAfriend //<--- extra information
displayName: John Doe
photoURL: https://firebase....
userfriends
xxsxaxacdadID1
trteretteteeID2: true
hgjkhgkhgjhgID3: true
trteretteteeID2
trteretteteeID2: truehttps://stackoverflow.com/questions/47732420
复制相似问题