如何仅在 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)
  )

这里的重要一点是&amp;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中的子数据?

获取现有的 firebase 子密钥

Firebase 使任务仅在主线程上执行,导致 Unity 冻结

如何在firebase自动生成的密钥下编辑子值

Firebase 在为 iOS 应用程序激活时询问密钥 ID

在具有子密钥uid(javascript)的firebase上检索数据