答案 0 :(得分:9)
来自文档中的Best practices for data structure:
避免嵌套数据
因为Firebase实时数据库允许最多嵌套数据32 水平很深,你可能会想到这应该是 默认结构。但是,当您在您的位置获取数据时 数据库,您还检索其所有子节点。另外,什么时候 您在数据库中的某个节点上授予某人读取或写入权限 还授予他们访问该节点下的所有数据的权限。因此,在 实践中,最好保持数据结构尽可能平坦。
这就是Firebase的工作原理:如果你得到一件物品,你也可以得到它的孩子。如果你不想要这个,你应该重组数据库。
答案 1 :(得分:6)
避免嵌套数据
由于Firebase实时数据库允许最多嵌套数据深度为32级,因此您可能会认为这应该是默认结构。但是,当您在数据库中的某个位置获取数据时,还会检索其所有子节点。此外,当您在数据库中的某个节点上授予某人读取或写入权限时,您还可以授予他们访问该节点下所有数据的权限。因此,在实践中,最好保持数据结构尽可能平坦。
以下是您的如何实现平面数据库以及如何检索位置密钥的结构。
{
"location": {
"punjab": {
"lahore": true,
"multan": true
},
"sindh": {
"karachi": true
}
},
"place": {
"lahore": {
"location": "punjab",
"details": {
"0": "model",
"1": "steel town"
}
},
"multan": {
"location": "punjab",
"contacts": {
"0": "myarea"
}
},
"karachi": {
"location": "sindh",
"contacts": {
"0": "hadeed",
"1": "Steel town"
}
}
}
}
以下是可用于检索位置密钥的代码。
private DatabaseReference mDatabase;
// ...
mDatabase = FirebaseDatabase.getInstance().getReference();
mLocation = mDatabase.child("location");
mPlace = mDatabase.child("place");
ValueEventListener placeListener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get Post object and use the values to update the UI
Place place = dataSnapshot.getValue(Place.class);
String location = place.location;
System.out.println(location);
}
};
mPlace.addValueEventListener(placeListener);
有关Firebase的详细信息:
答案 2 :(得分:1)
是的,你可以
ValueEventListener getValueListener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get data from firebase
Log.d("The name of child that you need:", dataSnapshot.getKey());
// ...
}
};
databaseReference.addValueEventListener(getValueListener );
了解详情:https://firebase.google.com/docs/database/android/read-and-write#listen_for_value_events
答案 3 :(得分:1)
虽然不建议在像Firebase这样的NoSQL数据库中嵌套数据,但要获取子节点的名称,您的代码将如下所示
DatabaseReference mainRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference locationref = mainRef.child("location");
final ArrayList<String> locationNames = new ArrayList<>();
locationref.addChildEventListener(new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
locationNames.add(dataSnapshot.getKey());
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
@Override
void onChildRemoved(DataSnapshot dataSnapshot) {
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
您现在可以使用locationNames执行您想要的操作。
答案 4 :(得分:1)
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference().child("location");
final ArrayList<String> statesArrayList= new ArrayList<>();
databaseReference.addChildEventListener(new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
statesArrayList.add(dataSnapshot.getKey());
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
@Override
void onChildRemoved(DataSnapshot dataSnapshot) {
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
答案 5 :(得分:0)
Firebase可以快速查找级别1的节点,因为它可以在级别32处查找。深度不是影响技术级别速度的因素,但多年使用Firebase的经验表明深层嵌套数据通常是齐头并进的有性能问题。例如,我重新阅读了您正在阅读的官方文档Best practices for data structure in Firebase和Structuring your Firebase Data correctly for a Complex App。
如果您不想更改实际的数据库结构并假设location
节点是Firebase root的直接子节点,请参阅以下代码:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference locationRef = rootRef.child("location");
ValueEventListener eventListener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
String key = ds.getKey();
Log.d("TAG", key);
}
}
@Override
public void onCancelled(DatabaseError databaseError) {}
};
locationRef.addListenerForSingleValueEvent(eventListener);
您的输出将是:
punjab
sindh
答案 6 :(得分:0)
我知道这个问题是在不久前针对Android平台问的,但是我一直在寻找解决方案,因此遇到了这个问题。我无法使用提供的答案,所以这是我找到的解决方案。这样只会得到孩子,别无其他。
这是用javascript编写的,但是您可以使用Java中的另一种方法来从REST端点发出请求。
const databaseURL = "https://example.firebaseio.com" // replace value with yours
const endpoint = "location"
const user = firebase.auth().currentUser
user.getIdToken()
.then(token => {
return fetch(`${databaseURL}/${endpoint}.json?auth=${token}&shallow=true`)
})
.then(response => {
return response.json()
})
.then(json => {
console.log({json}) // contains only the children
})
.catch(error => {
console.log(error.message)
})
这里重要的一点是&shallow=true
,否则您将在子节点中获取所有数据。
使用卷发
curl 'https://example.firebaseio.com/location.json?auth=INSERT_TOKEN&shallow=true'
这假设location
是根的子代。
通过查看docs
可以获得更多详细信息在调用此功能之前,必须确保Firebase中有currentUser。
此外,我会留意此处提到的有关适当的Firebase实时数据库结构的警告。但是,如果您已经在这个位置,那么可以提供帮助。
答案 7 :(得分:-1)
这就是你如何获得孩子名字
HashMap<String, Object> allData = (HashMap<String, Object>) dataSnapshot.getValue();
String[] yourChildArray = allData.keySet().toArray(new String[0]);