我正在使用 Java 和 Firebase 为大学项目开发 Android 应用程序。我想根据他们的职位存储在大学工作的教员的详细信息,如姓名、电子邮件、部门等。我在院系内创建了 3 个子节点 HOD、类(class)导师和讲师,您可以在此处看到。
我的问题是,当我想在这些子项中的任何一个中添加成员时,我想检查该成员的电子邮件 ID 是否存在于任何其他子项中。例如,我想在 HOD 子项中添加一个成员。如果此成员电子邮件存在于 Lecturers 子项中,则应显示 Toast 用户已作为讲师存在,否则应在 Lecturer 中添加成员。
我使用了这段代码。
post = "HOD";
databaseReference.child(post).orderByChild("email").equalTo(email).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
Toast.makeText(MainActivityAddFaculty.this, "User already exist in "+post, Toast.LENGTH_SHORT).show();
} else {
post = "Class mentor";
databaseReference.child(post).orderByChild("email").equalTo(email).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
Toast.makeText(MainActivityAddFaculty.this, "User already exist in "+post, Toast.LENGTH_SHORT).show();
} else {
post = "Lecturer";
databaseReference.child(post).orderByChild("email").equalTo(email).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
Toast.makeText(MainActivityAddFaculty.this, "User already exist in "+post, Toast.LENGTH_SHORT).show();
} else {
checkData();
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
Toast.makeText(MainActivityAddFaculty.this, databaseError.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
Toast.makeText(MainActivityAddFaculty.this, databaseError.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
Toast.makeText(MainActivityAddFaculty.this, databaseError.getMessage(), Toast.LENGTH_SHORT).show();
}
});
它工作正常,但它很长,而且需要时间检查。如果有任何更好的解决方案,将会非常有帮助。
这是我添加院系的完整代码。
public class MainActivityAddFaculty extends AppCompatActivity {
private TextInputLayout addName, addEmail;
private TextInputEditText addEditName, addEditEmail;
private Button addBtn;
private Spinner addPositionSpinner,addDeptSpinner,addYearSpinner;
private TextView addPosition,addDept,addYear;
private String sDept = "Select department",sPost = "Select position",sYear = "Select year";
private String position,department,year,post;
private boolean b = false;
private FirebaseDatabase firebaseDatabase;
private FirebaseStorage firebaseStorage;
private DatabaseReference databaseReference,databaseReference2;
private StorageReference storageReference;
LoadingDialog loadingDialog;
private String facultyID;
private String name,email;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_faculty);
setTitle("Add Hod");
assert getSupportActionBar() != null;
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
addName = findViewById(R.id.addFName);
addEmail = findViewById(R.id.addFEmail);
addEditName = findViewById(R.id.addFEditName);
addEditEmail = findViewById(R.id.addFEditEmail);
addBtn = findViewById(R.id.addFBtn);
addPositionSpinner = findViewById(R.id.addFPositionSpinner);
addPosition = findViewById(R.id.addFPosition);
addDeptSpinner = findViewById(R.id.addFDepartmentSpinner);
addDept = findViewById(R.id.addFDepartment);
addYearSpinner = findViewById(R.id.addFYearSpinner);
addYear = findViewById(R.id.addFYear);
addDeptSpinner.setVisibility(View.GONE);
addYearSpinner.setVisibility(View.GONE);
addDept.setVisibility(View.GONE);
addYear.setVisibility(View.GONE);
firebaseDatabase = FirebaseDatabase.getInstance();
databaseReference = firebaseDatabase.getReference("FACULTIES");
facultyID = databaseReference.push().getKey();
loadingDialog = new LoadingDialog(MainActivityAddFaculty.this);
//selectPosition();
//TODO:Select position
List<String> categories = new ArrayList<>();
categories.add(0,"Select position");
categories.add("HOD");
categories.add("Class mentor");
categories.add("Lecturer");
ArrayAdapter<String> dataAdapter;
dataAdapter = new ArrayAdapter(this,android.R.layout.simple_spinner_item,categories);
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
addPositionSpinner.setAdapter(dataAdapter);
addPositionSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
addPosition.setText(parent.getSelectedItem().toString());
test();
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
Toast.makeText(MainActivityAddFaculty.this, "Select a position", Toast.LENGTH_SHORT).show();
}
});
addBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
name = addEditName.getText().toString().trim();
email = addEditEmail.getText().toString().trim();
if (TextUtils.isEmpty(name)) {
Toast.makeText(MainActivityAddFaculty.this, "Enter name", Toast.LENGTH_SHORT).show();
}else {
if (TextUtils.isEmpty(email)) {
Toast.makeText(MainActivityAddFaculty.this, "Enter email.", Toast.LENGTH_SHORT).show();
} else {
checkData();
}
}
}
});
}
private void test(){
position = addPositionSpinner.getSelectedItem().toString();
if (position.equals(sPost)){
addDeptSpinner.setVisibility(View.GONE);
addYearSpinner.setVisibility(View.GONE);
addDept.setVisibility(View.GONE);
addYear.setVisibility(View.GONE);
}else if (position.equals("HOD")){
addDeptSpinner.setVisibility(View.VISIBLE);
addYearSpinner.setVisibility(View.GONE);
addDept.setVisibility(View.VISIBLE);
addYear.setVisibility(View.GONE);
} else if (position.equals("Class mentor")){
addDeptSpinner.setVisibility(View.VISIBLE);
addDept.setVisibility(View.VISIBLE);
addYearSpinner.setVisibility(View.VISIBLE);
addYear.setVisibility(View.VISIBLE);
} else if (position.equals("Lecturer")){
addDeptSpinner.setVisibility(View.GONE);
addYearSpinner.setVisibility(View.GONE);
addDept.setVisibility(View.GONE);
addYear.setVisibility(View.GONE);
} else {
addDeptSpinner.setVisibility(View.GONE);
addYearSpinner.setVisibility(View.GONE);
addDept.setVisibility(View.GONE);
addYear.setVisibility(View.GONE);
}
}
private void checkData(){
position = addPositionSpinner.getSelectedItem().toString();
department = addDeptSpinner.getSelectedItem().toString();
year = addYearSpinner.getSelectedItem().toString();
if (position.equals(sPost)){
Toast.makeText(this, "Select position", Toast.LENGTH_SHORT).show();
} else if (position.equals("HOD")){
if (department.equals(sDept)){
Toast.makeText(MainActivityAddFaculty.this, "Select department.", Toast.LENGTH_SHORT).show();
} else {
AddHOD addHOD = new AddHOD(name,position,department,email,facultyID);
databaseReference.child(position).child(facultyID).setValue(addHOD).addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
Toast.makeText(MainActivityAddFaculty.this, "Faculty added successfully", Toast.LENGTH_SHORT).show();
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Toast.makeText(MainActivityAddFaculty.this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
}else if (position.equals("Class mentor")){
//add Class mentor process started
if (!department.equals(sDept)){
if (!year.equals(sYear)) {
AddClassMentor addClassMentor = new AddClassMentor(name, position, department, year, email, facultyID);
databaseReference.child(position).child(facultyID).setValue(addClassMentor).addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
Toast.makeText(MainActivityAddFaculty.this, "Faculty added successfully", Toast.LENGTH_SHORT).show();
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Toast.makeText(MainActivityAddFaculty.this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}else {
Toast.makeText(this, "Select year.", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(this, "Select department", Toast.LENGTH_SHORT).show();
}
} else if (position.equals("Lecturer")){
AddLecturer addLecturer = new AddLecturer(name,position,email,facultyID);
databaseReference.child(position).child(facultyID).setValue(addLecturer).addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
Toast.makeText(MainActivityAddFaculty.this, "Faculty added successfully", Toast.LENGTH_SHORT).show();
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Toast.makeText(MainActivityAddFaculty.this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
} else {
Toast.makeText(this, "Entry is pending.", Toast.LENGTH_SHORT).show();
}
}
}
最佳答案
Firebase 的查询适用于节点列表。由于您有一个层次结构,因此您需要为其中的每个列表触发相同的查询,就像您今天所做的那样。
与往常一样,在处理 NoSQL 数据库时,解决方案是以一种使用例最简单的方式对数据进行建模。如果您想搜索所有成员,请存储单个成员列表:
"members": {
"$memberid": {
"email": "membersemail@institute.edu",
"memberType": "Class mentor" // or "HOD" or "Lecturer"
}
}
使用上述结构,您只需执行一个查询即可查找具有特定电子邮件地址的所有成员。
<小时/>您可以使用上述结构来替换您当前拥有的三个结构,或者您可以将其用作仅用于此用例的附加结构。选择哪一种取决于您应用中的其他用例,没有一种解决方案适合所有应用,只有适合您的解决方案。
<小时/>像您在这里所做的那样在值之间强制执行唯一性,随着时间的推移将导致可扩展性问题,因为您:
- 需要搜索所有成员,随着成员数量的增加,这会花费更多时间。
- 更重要的是:您需要使用事务来插入新用户,以减少多个用户同时声明同一电子邮件地址的可能性。
- 这会导致第二个扩展问题,因为您需要在不断增长的
/members
节点上运行该事务。 - 最后:恶意用户可以通过编写自己的代码来绕过交易,并仍然声称拥有任何电子邮件地址。
只有当您使用这些值作为列表中的键时,才能真正强制执行 Firebase 上的唯一性,因此需要维护一个(附加)电子邮件地址列表。
有关此内容的更多信息,请参阅:
关于java - 检查 Android 中的子 Firebase 数据库中是否存在值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61710479/