Reactjs 每次用户登录时firebase DB中的新节点

Reactjs 每次用户登录时firebase DB中的新节点,reactjs,firebase,Reactjs,Firebase,我正在React中创建测试/检查应用程序。这些问题是预定义的,并存储在一个节点的firebase数据库中,我想将进行的测试存储在另一个节点中。但是我想为每次新的考试尝试添加新的子节点 不幸的是,到目前为止,结果已被取代 我需要这样的结构: "answers": { "0": { "user": "Mr X", "testDone": true, "result": 3, "questions": { "0": {

我正在React中创建测试/检查应用程序。这些问题是预定义的,并存储在一个节点的firebase数据库中,我想将进行的测试存储在另一个节点中。但是我想为每次新的考试尝试添加新的子节点

不幸的是,到目前为止,结果已被取代

我需要这样的结构:

 "answers": {
    "0": {
      "user": "Mr X",
      "testDone": true,
      "result": 3,
      "questions": {
        "0": {
          "content": "How much is 2 x 2?",
          "selectedAnswer": "A",
          "correctAnswer": "A"
        },
        "1": {
          "content": "How much is 2 + 2?",
          "selectedAnswer": "B",
          "correctAnswer": "B"
        },
        "2": {
          "content": "How much is 2 / 2?",
          "selectedAnswer": "C",
          "correctAnswer": "C"
        }
      }
    },
    "1": {
      "user": "Mr Y",
      "testDone": true,
      "result": 1,
      "questions": {
        "0": {
          "content": "How much is 2 x 2?",
          "selectedAnswer": "A",
          "correctAnswer": "A"
        },
        "1": {
          "content": "How much is 2 + 2?",
          "selectedAnswer": "C",
          "correctAnswer": "B"
        },
        "2": {
          "content": "How much is 2 / 2?",
          "selectedAnswer": "B",
          "correctAnswer": "C"
        }
      }
    },
    "2": {
      "user": "Mr Z",
      "testDone": true,
      "result": 2,
      "questions": {
        "0": {
          "content": "How much is 2 x 2?",
          "selectedAnswer": "A",
          "correctAnswer": "A"
        },
        "1": {
          "content": "How much is 2 + 2?",
          "selectedAnswer": "B",
          "correctAnswer": "B"
        },
        "2": {
          "content": "How much is 2 / 2?",
          "selectedAnswer": "A",
          "correctAnswer": "C"
        }
      }
    }
  }
}
在未来,我还想防止用户进行一次以上的考试。因此,我需要在身份验证过程中检查特定用户名是否已存在于answers对象中,或者预定义answers对象,并仅对位于该对象内且属性testDone的值设置为false的用户进行身份验证


因此,我的问题是如何强制firebase为新的考试尝试添加新节点,然后将应用程序状态与特定子节点同步(每次不同的子节点将被同步)。

您可以有一个节点只用于测试结果,每次用户参加测试,它们的结果将使用每个新结果的唯一ID添加到该节点。这样,它们将不会覆盖以前保存的结果,您也可以将用户ID绑定到结果

//Database reference
var firebaseDb = firebase.database().ref.child("completed_tests");

//example score from a test
var usersScore = 9;

//Creating a new reference with a newly generated key, unique to this node.
var resultsRef = firebaseDb.push();

//Getting the unique key so we can use it to save data to it.
var newId = resultsRef.key;

//Adding data to the node we created above, inside the "completed_tests" node.
firebaseDb.child(newId).child("grade").set(userScore);
数据库可能类似于此示例

    {
    "root": {
        "completed_tests": {
            "uniqueTestId_12345": {
                "Which_test": "test_1",
                "userId": "1234_uid_of_test_taker",
                "grade": 9
            },
            "uniqueTestId_23456": {
                "grade": 5
            },
            "uniqueTestId_34567": {
                "grade": 7
            }
        },
        "tests": {
            "test_1": {
                "Q1": "Who am I?",
                "Q2": "..."
            },
            "test_2": {
                "Q1": "Who are You?",
                "Q2": "..."
            }
        }
    }
}

上面是一个使用JavaScript使用唯一ID保存数据的简单示例。显然,您可以将更多数据保存到节点,可能是单个答案、分数、时间戳、uid、指向原始测试的指针等。

谢谢您的回答。现在,我的componentDidMount()函数如下所示:

componentDidMount() {
    var firebaseDb = firebaseApp.database().ref("completed_tests");
    var resultsRef = firebaseDb.push();
    var newId = resultsRef.key;
    this.ref = fbase.syncState("/completed_tests/" + newId + "/user/", {
      context: this,
      asArray: true,
      state: "user"
    });
    this.ref = fbase.syncState("/completed_tests/" + newId + "/answers/", {
      context: this,
      asArray: true,
      state: "answers"
    });
    this.ref = fbase.syncState("/completed_tests/" + newId + "/result/", {
      context: this,
      asArray: true,
      state: "result"
    });
  }
它工作得很好,但还有一件事我想改进。现在,每个节点引用都由奇怪的字符串组成。我更希望节点的名称与登录名(电子邮件地址)相同,但当然要将“.”替换为firabase允许的任何符号(即“”)。因此,我将身份验证功能更改为:

  authenticate = event => {
    event.preventDefault();
    firebaseApp
      .auth()
      .signInWithEmailAndPassword(this.state.email, this.state.password)
      .then(() => {
        this.setState({
          loggedIn: 1,
          user: this.state.email
        });
      })
      .catch(() => {
        console.log("Unable to authenticate");
      });
    firebaseApp
      .database()
      .ref("/users/")
      .once("value")
      .then(snapshot => {
        for (var key in snapshot.val()) {
          if (this.state.email.replace(".", "_") === key) {
            this.setState({
              loggedIn: 2
            });
            console.log("you have already filled the test");
          } else {
            console.log("it's first time you arte taking this test");
          }
        }
      });
  };
loggedinstate的值用于控制要显示的内容,因此我可以防止用户多次参加测试。但现在我想添加新节点(即用户登录)并将所有其他对象发送到其中。添加此节点不是问题,但我无法通过此新节点的绑定状态。如果我把它放在authenticate函数中,它就不起作用了,因为身份验证是在添加绑定代码之后进行的。 componentDidMount()内部的绑定也不起作用,因为在调用componentDidMount()函数后,连接到登录名的状态值发生了更改


有什么方法可以克服这个问题吗?

您的代码中有哪些没有按预期的方式工作?请将您的问题编辑为具体问题。