如何仅在 Firebase 中获取子密钥
Posted
技术标签:
【中文标题】如何仅在 Firebase 中获取子密钥【英文标题】:How to only get child keys in Firebase 【发布时间】:2017-06-15 07:34:24 【问题描述】:我只想显示位置的孩子,即信德省和旁遮普省(不是他们的孩子)。有可能吗,如果可以,我该怎么做?
【问题讨论】:
使用查询 【参考方案1】:来自文档中的Best practices for data structure:
避免嵌套数据
因为 Firebase 实时数据库允许嵌套最多 32 个数据 层次很深,你可能会认为这应该是 默认结构。但是,当您在您的 数据库,您还可以检索其所有子节点。此外,当 您授予某人对数据库中某个节点的读取或写入访问权限,您 还授予他们访问该节点下所有数据的权限。因此,在 实践中,最好保持数据结构尽可能平坦。
这就是 Firebase 的工作原理:如果你得到一个项目,你也会得到它的孩子。如果你不想这样,你应该重组数据库。
【讨论】:
【参考方案2】:避免嵌套数据
由于 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 的更多信息:
Firebase Security & Rules【讨论】:
【参考方案3】: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)
);
【讨论】:
【参考方案4】:是的,你可以
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
【讨论】:
请注意:dataSnapshot.getKey() 将返回孩子的名字——我认为这就是你所需要的。【参考方案5】:尽管在 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 来做您想做的事。
【讨论】:
【参考方案6】:Firebase 在第 1 级查找节点的速度与在第 32 级查找节点的速度一样快。在技术层面上,深度并不是影响速度的因素,但多年使用 Firebase 的经验表明,深度嵌套的数据通常是齐头并进的有性能问题。例如,我建议您阅读官方文档,Best practices for data structure in Firebase 和 Structuring your Firebase Data correctly for a Complex App。
如果您不想更改实际的数据库结构并假设 location
节点是 Firebase 根的直接子节点,请查看以下代码:
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
【讨论】:
【参考方案7】:我知道这个问题是不久前针对 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 这将是
curl 'https://example.firebaseio.com/location.json?auth=INSERT_TOKEN&shallow=true'
这假定 location
是根的子节点。
更多详情请查看docs
在调用它之前,您必须确保在 firebase 中有 currentUser 可用。
另外,我会注意此处提到的有关正确的 firebase 实时数据库结构的警告。但是,如果您已经在这个位置,那么这会有所帮助。
【讨论】:
【参考方案8】:这就是你如何获得孩子的名字
HashMap<String, Object> allData = (HashMap<String, Object>) dataSnapshot.getValue();
String[] yourChildArray = allData.keySet().toArray(new String[0]);
【讨论】:
以上是关于如何仅在 Firebase 中获取子密钥的主要内容,如果未能解决你的问题,请参考以下文章
Firebase 使任务仅在主线程上执行,导致 Unity 冻结