首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >火基非正态化数据一致性问题

火基非正态化数据一致性问题
EN

Stack Overflow用户
提问于 2017-12-09 19:39:28
回答 1查看 386关注 0票数 4

我目前正在使用Ionic CLI 3.19和Cordova CLI 7.1.0 (@离子型应用程序-脚本3.1.4)

我目前面临的问题是,每次相关数据从其他地方更改时,我都应该同时更新朋友节点值。我想用一些截图来澄清我的目标,以使它更清楚。

从下面的图像中可以看到,每个子节点都由一个用户数组组成,其中有一个用户id作为好友节点的键。我之所以将其存储为数组,是因为每个用户都可能有许多朋友。在本例中,Jeff有一个朋友,即John,反之亦然。

当用户节点中的数据因某种原因而更改时,我希望朋友节点中的相关数据也能被更新。

例如,当Jeff更改了他的配置文件照片或statusMessage时,与Jeff的uid匹配的朋友节点中的所有uid都需要根据用户更改的内容进行更新。

user-service.ts

代码语言:javascript
运行
复制
    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方法两次的情况下更新多个位置的数据。

代码语言:javascript
运行
复制
// 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

代码语言:javascript
运行
复制
    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

代码语言:javascript
运行
复制
    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);
    });
  }

下面的代码在将状态更新到联机而不是脱机时运行良好。

我不认为这是正确的方法。

代码语言:javascript
运行
复制
    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数据库中。

,有人能帮我吗?:(

EN

回答 1

Stack Overflow用户

发布于 2017-12-11 01:31:42

我认为您这样做是正确的,并且您的多路径更新方向是正确的。但假设有几个用户可以有几个朋友,我就错过了朋友表中的一个循环。

您应该有表usersfriendsuserFriend。最后一个表就像在friends中查找用户的快捷方式,您需要迭代每个朋友以找到需要更新的用户。

我在我的first_app_example角度4+火力基础上做了一个不同的方法。我从客户端删除了这个过程,并通过云函数中的onUpdate()将它添加到服务器中。

代码波纹管中,当用户更改名称时,云函数将在用户已经编写的每个评论中执行和更新名称。在我的例子中,客户端不知道非正规化。

代码语言:javascript
运行
复制
//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”。您可以通过以下两个步骤访问所有朋友的信息:

代码语言:javascript
运行
复制
 let friends: string[];
 for each friend in usrService.getFriend(userID)
    friends.push(usrService.getUser(friend))

问:你的意思是我应该创建一个查找表?

在你的问题中提到的剪辑,David给了我们一个如何去造势的例子。原来他有usersevents。在非正规化中,他创建了类似于vlookup的eventAttendees (就像您难过)。

问:你能举个例子吗?

好的。我删除了一些用户信息,并添加了一个额外的字段friendshipTypes

代码语言:javascript
运行
复制
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: true
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47732420

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档